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__) 
  30     #include "wx/dynarray.h" 
  34     #include "wx/settings.h" 
  35     #include "wx/bitmap.h" 
  36     #include "wx/dcmemory.h" 
  37     #include "wx/control.h" 
  38     #include "wx/app.h"         // for GetComCtl32Version 
  41 #include "wx/toolbar.h" 
  42 #include "wx/sysopt.h" 
  45 #include "wx/msw/private.h" 
  48 #include "wx/msw/uxtheme.h" 
  51 // include <commctrl.h> "properly" 
  52 #include "wx/msw/wrapcctl.h" 
  54 // this define controls whether the code for button colours remapping (only 
  55 // useful for 16 or 256 colour images) is active at all, it's always turned off 
  56 // for CE where it doesn't compile (and is probably not needed anyhow) and may 
  57 // also be turned off for other systems if you always use 24bpp images and so 
  60     #define wxREMAP_BUTTON_COLOURS 
  61 #endif // !__WXWINCE__ 
  63 // ---------------------------------------------------------------------------- 
  65 // ---------------------------------------------------------------------------- 
  67 // these standard constants are not always defined in compilers headers 
  71     #define TBSTYLE_LIST            0x1000 
  72     #define TBSTYLE_FLAT            0x0800 
  75 #ifndef TBSTYLE_TRANSPARENT 
  76     #define TBSTYLE_TRANSPARENT     0x8000 
  79 #ifndef TBSTYLE_TOOLTIPS 
  80     #define TBSTYLE_TOOLTIPS        0x0100 
  85     #define TB_SETSTYLE             (WM_USER + 56) 
  86     #define TB_GETSTYLE             (WM_USER + 57) 
  90     #define TB_HITTEST              (WM_USER + 69) 
  94     #define TB_GETMAXSIZE           (WM_USER + 83) 
  97 // these values correspond to those used by comctl32.dll 
  98 #define DEFAULTBITMAPX   16 
  99 #define DEFAULTBITMAPY   15 
 101 // ---------------------------------------------------------------------------- 
 103 // ---------------------------------------------------------------------------- 
 105 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
) 
 117         style ( wxNO_BORDER | wxTB_HORIZONTAL) 
 126 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 127     EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent
) 
 128     EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged
) 
 129     EVT_ERASE_BACKGROUND(wxToolBar::OnEraseBackground
) 
 132 // ---------------------------------------------------------------------------- 
 134 // ---------------------------------------------------------------------------- 
 136 class wxToolBarTool 
: public wxToolBarToolBase
 
 139     wxToolBarTool(wxToolBar 
*tbar
, 
 141                   const wxString
& label
, 
 142                   const wxBitmap
& bmpNormal
, 
 143                   const wxBitmap
& bmpDisabled
, 
 145                   wxObject 
*clientData
, 
 146                   const wxString
& shortHelp
, 
 147                   const wxString
& longHelp
) 
 148         : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 149                             clientData
, shortHelp
, longHelp
) 
 154     wxToolBarTool(wxToolBar 
*tbar
, wxControl 
*control
) 
 155         : wxToolBarToolBase(tbar
, control
) 
 160     virtual void SetLabel(const wxString
& label
) 
 162         if ( label 
== m_label 
) 
 165         wxToolBarToolBase::SetLabel(label
); 
 167         // we need to update the label shown in the toolbar because it has a 
 168         // pointer to the internal buffer of the old label 
 170         // TODO: use TB_SETBUTTONINFO 
 173     // set/get the number of separators which we use to cover the space used by 
 174     // a control in the toolbar 
 175     void SetSeparatorsCount(size_t count
) { m_nSepCount 
= count
; } 
 176     size_t GetSeparatorsCount() const { return m_nSepCount
; } 
 181     DECLARE_NO_COPY_CLASS(wxToolBarTool
) 
 185 // ============================================================================ 
 187 // ============================================================================ 
 189 // ---------------------------------------------------------------------------- 
 191 // ---------------------------------------------------------------------------- 
 193 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 194                                          const wxString
& label
, 
 195                                          const wxBitmap
& bmpNormal
, 
 196                                          const wxBitmap
& bmpDisabled
, 
 198                                          wxObject 
*clientData
, 
 199                                          const wxString
& shortHelp
, 
 200                                          const wxString
& longHelp
) 
 202     return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 203                              clientData
, shortHelp
, longHelp
); 
 206 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 208     return new wxToolBarTool(this, control
); 
 211 // ---------------------------------------------------------------------------- 
 212 // wxToolBar construction 
 213 // ---------------------------------------------------------------------------- 
 215 void wxToolBar::Init() 
 218     m_disabledImgList 
= NULL
; 
 222     m_defaultWidth 
= DEFAULTBITMAPX
; 
 223     m_defaultHeight 
= DEFAULTBITMAPY
; 
 228 bool wxToolBar::Create(wxWindow 
*parent
, 
 233                        const wxString
& name
) 
 235     // common initialisation 
 236     if ( !CreateControl(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) ) 
 239     // MSW-specific initialisation 
 240     if ( !MSWCreateToolbar(pos
, size
) ) 
 243     wxSetCCUnicodeFormat(GetHwnd()); 
 245     // workaround for flat toolbar on Windows XP classic style: we have to set 
 246     // the style after creating the control; doing it at creation time doesn't work 
 248     if ( style 
& wxTB_FLAT 
) 
 250         LRESULT style 
= ::SendMessage(GetHwnd(), TB_GETSTYLE
, 0, 0L); 
 252         if ( !(style 
& TBSTYLE_FLAT
) ) 
 253             ::SendMessage(GetHwnd(), TB_SETSTYLE
, 0, style 
| TBSTYLE_FLAT
); 
 255 #endif // wxUSE_UXTHEME 
 260 bool wxToolBar::MSWCreateToolbar(const wxPoint
& pos
, const wxSize
& size
) 
 262     if ( !MSWCreateControl(TOOLBARCLASSNAME
, wxEmptyString
, pos
, size
) ) 
 265     // toolbar-specific post initialisation 
 266     ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE
, sizeof(TBBUTTON
), 0); 
 271 void wxToolBar::Recreate() 
 273     const HWND hwndOld 
= GetHwnd(); 
 276         // we haven't been created yet, no need to recreate 
 280     // get the position and size before unsubclassing the old toolbar 
 281     const wxPoint pos 
= GetPosition(); 
 282     const wxSize size 
= GetSize(); 
 286     if ( !MSWCreateToolbar(pos
, size
) ) 
 289         wxFAIL_MSG( _T("recreating the toolbar failed") ); 
 294     // reparent all our children under the new toolbar 
 295     for ( wxWindowList::compatibility_iterator node 
= m_children
.GetFirst(); 
 297           node 
= node
->GetNext() ) 
 299         wxWindow 
*win 
= node
->GetData(); 
 300         if ( !win
->IsTopLevel() ) 
 301             ::SetParent(GetHwndOf(win
), GetHwnd()); 
 304     // only destroy the old toolbar now -- 
 305     // after all the children had been reparented 
 306     ::DestroyWindow(hwndOld
); 
 308     // it is for the old bitmap control and can't be used with the new one 
 311         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 315     if ( m_disabledImgList 
) 
 317         delete m_disabledImgList
; 
 318         m_disabledImgList 
= NULL
; 
 324 wxToolBar::~wxToolBar() 
 326     // we must refresh the frame size when the toolbar is deleted but the frame 
 327     // is not - otherwise toolbar leaves a hole in the place it used to occupy 
 328     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
 329     if ( frame 
&& !frame
->IsBeingDeleted() ) 
 330         frame
->SendSizeEvent(); 
 333         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 335     delete m_disabledImgList
; 
 338 wxSize 
wxToolBar::DoGetBestSize() const 
 343     if ( !::SendMessage(GetHwnd(), TB_GETMAXSIZE
, 0, (LPARAM
)&size
) ) 
 345         // maybe an old (< 0x400) Windows version? try to approximate the 
 346         // toolbar size ourselves 
 347         sizeBest 
= GetToolSize(); 
 348         sizeBest
.y 
+= 2 * ::GetSystemMetrics(SM_CYBORDER
); // Add borders 
 349         sizeBest
.x 
*= GetToolsCount(); 
 351         // reverse horz and vertical components if necessary 
 352         if ( HasFlag(wxTB_VERTICAL
) ) 
 355             sizeBest
.x 
= sizeBest
.y
; 
 361         sizeBest
.x 
= size
.cx
; 
 362         sizeBest
.y 
= size
.cy
; 
 365     CacheBestSize(sizeBest
); 
 370 WXDWORD 
wxToolBar::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 372     // toolbars never have border, giving one to them results in broken 
 374     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 376                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 379     if ( !(style 
& wxTB_NO_TOOLTIPS
) ) 
 380         msStyle 
|= TBSTYLE_TOOLTIPS
; 
 382     if ( style 
& (wxTB_FLAT 
| wxTB_HORZ_LAYOUT
) ) 
 384         // static as it doesn't change during the program lifetime 
 385         static int s_verComCtl 
= wxApp::GetComCtl32Version(); 
 387         // comctl32.dll 4.00 doesn't support the flat toolbars and using this 
 388         // style with 6.00 (part of Windows XP) leads to the toolbar with 
 389         // incorrect background colour - and not using it still results in the 
 390         // correct (flat) toolbar, so don't use it there 
 391         if ( s_verComCtl 
> 400 && s_verComCtl 
< 600 ) 
 392             msStyle 
|= TBSTYLE_FLAT 
| TBSTYLE_TRANSPARENT
; 
 394         if ( s_verComCtl 
>= 470 && style 
& wxTB_HORZ_LAYOUT 
) 
 395             msStyle 
|= TBSTYLE_LIST
; 
 398     if ( style 
& wxTB_NODIVIDER 
) 
 399         msStyle 
|= CCS_NODIVIDER
; 
 401     if ( style 
& wxTB_NOALIGN 
) 
 402         msStyle 
|= CCS_NOPARENTALIGN
; 
 404     if ( style 
& wxTB_VERTICAL 
) 
 410 // ---------------------------------------------------------------------------- 
 411 // adding/removing tools 
 412 // ---------------------------------------------------------------------------- 
 414 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 416     // nothing special to do here - we really create the toolbar buttons in 
 420     InvalidateBestSize(); 
 424 bool wxToolBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 426     // the main difficulty we have here is with the controls in the toolbars: 
 427     // as we (sometimes) use several separators to cover up the space used by 
 428     // them, the indices are not the same for us and the toolbar 
 430     // first determine the position of the first button to delete: it may be 
 431     // different from pos if we use several separators to cover the space used 
 433     wxToolBarToolsList::compatibility_iterator node
; 
 434     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 436         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 439             // let node point to the next node in the list 
 440             node 
= node
->GetNext(); 
 445         if ( tool2
->IsControl() ) 
 446             pos 
+= ((wxToolBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 449     // now determine the number of buttons to delete and the area taken by them 
 450     size_t nButtonsToDelete 
= 1; 
 452     // get the size of the button we're going to delete 
 454     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 456         wxLogLastError(_T("TB_GETITEMRECT")); 
 459     int width 
= r
.right 
- r
.left
; 
 461     if ( tool
->IsControl() ) 
 463         nButtonsToDelete 
= ((wxToolBarTool 
*)tool
)->GetSeparatorsCount(); 
 464         width 
*= nButtonsToDelete
; 
 465         tool
->GetControl()->Destroy(); 
 468     // do delete all buttons 
 469     m_nButtons 
-= nButtonsToDelete
; 
 470     while ( nButtonsToDelete
-- > 0 ) 
 472         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 474             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 482     // and finally reposition all the controls after this button (the toolbar 
 483     // takes care of all normal items) 
 484     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 486         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 487         if ( tool2
->IsControl() ) 
 490             wxControl 
*control 
= tool2
->GetControl(); 
 491             control
->GetPosition(&x
, NULL
); 
 492             control
->Move(x 
- width
, wxDefaultCoord
); 
 496     InvalidateBestSize(); 
 501 void wxToolBar::CreateDisabledImageList() 
 503     if (m_disabledImgList 
!= NULL
) 
 505         delete m_disabledImgList
; 
 506         m_disabledImgList 
= NULL
; 
 509     // as we can't use disabled image list with older versions of comctl32.dll, 
 510     // don't even bother creating it 
 511     if ( wxApp::GetComCtl32Version() >= 470 ) 
 513         // search for the first disabled button img in the toolbar, if any 
 514         for ( wxToolBarToolsList::compatibility_iterator
 
 515                 node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 517             wxToolBarToolBase 
*tool 
= node
->GetData(); 
 518             wxBitmap bmpDisabled 
= tool
->GetDisabledBitmap(); 
 519             if ( bmpDisabled
.Ok() ) 
 521                 m_disabledImgList 
= new wxImageList
 
 525                                             bmpDisabled
.GetMask() != NULL
, 
 532         // we don't have any disabled bitmaps 
 536 bool wxToolBar::Realize() 
 538     const size_t nTools 
= GetToolsCount(); 
 543     const bool isVertical 
= HasFlag(wxTB_VERTICAL
); 
 545 #ifdef wxREMAP_BUTTON_COLOURS 
 546     // don't change the values of these constants, they can be set from the 
 547     // user code via wxSystemOptions 
 556     // the user-specified option overrides anything, but if it wasn't set, only 
 557     // remap the buttons on 8bpp displays as otherwise the bitmaps usually look 
 558     // much worse after remapping 
 559     static const wxChar 
*remapOption 
= wxT("msw.remap"); 
 560     const int remapValue 
= wxSystemOptions::HasOption(remapOption
) 
 561                                 ? wxSystemOptions::GetOptionInt(remapOption
) 
 562                                 : wxDisplayDepth() <= 8 ? Remap_Buttons
 
 565 #endif // wxREMAP_BUTTON_COLOURS 
 567     // delete all old buttons, if any 
 568     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 570         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 572             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 576     // First, add the bitmap: we use one bitmap for all toolbar buttons 
 577     // ---------------------------------------------------------------- 
 579     wxToolBarToolsList::compatibility_iterator node
; 
 583     if ( HasFlag(wxTB_NOICONS
) ) 
 585         // no icons, don't leave space for them 
 589     else // do show icons 
 591         // if we already have a bitmap, we'll replace the existing one -- 
 592         // otherwise we'll install a new one 
 593         HBITMAP oldToolBarBitmap 
= (HBITMAP
)m_hBitmap
; 
 595         sizeBmp
.x 
= m_defaultWidth
; 
 596         sizeBmp
.y 
= m_defaultHeight
; 
 598         const wxCoord totalBitmapWidth  
= m_defaultWidth 
* 
 599                                           wx_truncate_cast(wxCoord
, nTools
), 
 600                       totalBitmapHeight 
= m_defaultHeight
; 
 602         // Create a bitmap and copy all the tool bitmaps into it 
 603         wxMemoryDC dcAllButtons
; 
 604         wxBitmap 
bitmap(totalBitmapWidth
, totalBitmapHeight
); 
 605         dcAllButtons
.SelectObject(bitmap
); 
 607 #ifdef wxREMAP_BUTTON_COLOURS 
 608         if ( remapValue 
!= Remap_TransparentBg 
) 
 609 #endif // wxREMAP_BUTTON_COLOURS 
 611             // VZ: why do we hardcode grey colour for CE? 
 612             dcAllButtons
.SetBackground(wxBrush( 
 614                                         wxColour(0xc0, 0xc0, 0xc0) 
 615 #else // !__WXWINCE__ 
 616                                         GetBackgroundColour() 
 617 #endif // __WXWINCE__/!__WXWINCE__ 
 619             dcAllButtons
.Clear(); 
 622         m_hBitmap 
= bitmap
.GetHBITMAP(); 
 623         HBITMAP hBitmap 
= (HBITMAP
)m_hBitmap
; 
 625 #ifdef wxREMAP_BUTTON_COLOURS 
 626         if ( remapValue 
== Remap_Bg 
) 
 628             dcAllButtons
.SelectObject(wxNullBitmap
); 
 630             // Even if we're not remapping the bitmap 
 631             // content, we still have to remap the background. 
 632             hBitmap 
= (HBITMAP
)MapBitmap((WXHBITMAP
) hBitmap
, 
 633                 totalBitmapWidth
, totalBitmapHeight
); 
 635             dcAllButtons
.SelectObject(bitmap
); 
 637 #endif // wxREMAP_BUTTON_COLOURS 
 639         // the button position 
 642         // the number of buttons (not separators) 
 645         CreateDisabledImageList(); 
 646         for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 648             wxToolBarToolBase 
*tool 
= node
->GetData(); 
 649             if ( tool
->IsButton() ) 
 651                 const wxBitmap
& bmp 
= tool
->GetNormalBitmap(); 
 653                 const int w 
= bmp
.GetWidth(); 
 654                 const int h 
= bmp
.GetHeight(); 
 658                     int xOffset 
= wxMax(0, (m_defaultWidth 
- w
)/2); 
 659                     int yOffset 
= wxMax(0, (m_defaultHeight 
- h
)/2); 
 661                     // notice the last parameter: do use mask 
 662                     dcAllButtons
.DrawBitmap(bmp
, x 
+ xOffset
, yOffset
, true); 
 666                     wxFAIL_MSG( _T("invalid tool button bitmap") ); 
 669                 // also deal with disabled bitmap if we want to use them 
 670                 if ( m_disabledImgList 
) 
 672                     wxBitmap bmpDisabled 
= tool
->GetDisabledBitmap(); 
 673 #if wxUSE_IMAGE && wxUSE_WXDIB 
 674                     if ( !bmpDisabled
.Ok() ) 
 676                         // no disabled bitmap specified but we still need to 
 677                         // fill the space in the image list with something, so 
 678                         // we grey out the normal bitmap 
 680                         wxCreateGreyedImage(bmp
.ConvertToImage(), imgGreyed
); 
 682 #ifdef wxREMAP_BUTTON_COLOURS 
 683                         if ( remapValue 
== Remap_Buttons 
) 
 685                             // we need to have light grey background colour for 
 686                             // MapBitmap() to work correctly 
 687                             for ( int y 
= 0; y 
< h
; y
++ ) 
 689                                 for ( int x 
= 0; x 
< w
; x
++ ) 
 691                                     if ( imgGreyed
.IsTransparent(x
, y
) ) 
 692                                         imgGreyed
.SetRGB(x
, y
, 
 694                                                          wxLIGHT_GREY
->Green(), 
 695                                                          wxLIGHT_GREY
->Blue()); 
 699 #endif // wxREMAP_BUTTON_COLOURS 
 701                         bmpDisabled 
= wxBitmap(imgGreyed
); 
 703 #endif // wxUSE_IMAGE 
 705 #ifdef wxREMAP_BUTTON_COLOURS 
 706                     if ( remapValue 
== Remap_Buttons 
) 
 707                         MapBitmap(bmpDisabled
.GetHBITMAP(), w
, h
); 
 708 #endif // wxREMAP_BUTTON_COLOURS 
 710                     m_disabledImgList
->Add(bmpDisabled
); 
 713                 // still inc width and number of buttons because otherwise the 
 714                 // subsequent buttons will all be shifted which is rather confusing 
 715                 // (and like this you'd see immediately which bitmap was bad) 
 721         dcAllButtons
.SelectObject(wxNullBitmap
); 
 723         // don't delete this HBITMAP! 
 724         bitmap
.SetHBITMAP(0); 
 726 #ifdef wxREMAP_BUTTON_COLOURS 
 727         if ( remapValue 
== Remap_Buttons 
) 
 729             // Map to system colours 
 730             hBitmap 
= (HBITMAP
)MapBitmap((WXHBITMAP
) hBitmap
, 
 731                                          totalBitmapWidth
, totalBitmapHeight
); 
 733 #endif // wxREMAP_BUTTON_COLOURS 
 735         bool addBitmap 
= true; 
 737         if ( oldToolBarBitmap 
) 
 739 #ifdef TB_REPLACEBITMAP 
 740             if ( wxApp::GetComCtl32Version() >= 400 ) 
 742                 TBREPLACEBITMAP replaceBitmap
; 
 743                 replaceBitmap
.hInstOld 
= NULL
; 
 744                 replaceBitmap
.hInstNew 
= NULL
; 
 745                 replaceBitmap
.nIDOld 
= (UINT
) oldToolBarBitmap
; 
 746                 replaceBitmap
.nIDNew 
= (UINT
) hBitmap
; 
 747                 replaceBitmap
.nButtons 
= nButtons
; 
 748                 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP
, 
 749                                     0, (LPARAM
) &replaceBitmap
) ) 
 751                     wxFAIL_MSG(wxT("Could not replace the old bitmap")); 
 754                 ::DeleteObject(oldToolBarBitmap
); 
 760 #endif // TB_REPLACEBITMAP 
 762                 // we can't replace the old bitmap, so we will add another one 
 763                 // (awfully inefficient, but what else to do?) and shift the bitmap 
 764                 // indices accordingly 
 767                 bitmapId 
= m_nButtons
; 
 771         if ( addBitmap 
) // no old bitmap or we can't replace it 
 773             TBADDBITMAP addBitmap
; 
 775             addBitmap
.nID 
= (UINT
) hBitmap
; 
 776             if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP
, 
 777                                (WPARAM
) nButtons
, (LPARAM
)&addBitmap
) == -1 ) 
 779                 wxFAIL_MSG(wxT("Could not add bitmap to toolbar")); 
 783         if ( m_disabledImgList 
) 
 785             HIMAGELIST oldImageList 
= (HIMAGELIST
) 
 786                 ::SendMessage(GetHwnd(), 
 787                               TB_SETDISABLEDIMAGELIST
, 
 789                               (LPARAM
)GetHimagelistOf(m_disabledImgList
)); 
 791             // delete previous image list if any 
 793                 ::DeleteObject( oldImageList 
); 
 797     // don't call SetToolBitmapSize() as we don't want to change the values of 
 798     // m_defaultWidth/Height 
 799     if ( !::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, 
 800                         MAKELONG(sizeBmp
.x
, sizeBmp
.y
)) ) 
 802         wxLogLastError(_T("TB_SETBITMAPSIZE")); 
 805     // Next add the buttons and separators 
 806     // ----------------------------------- 
 808     TBBUTTON 
*buttons 
= new TBBUTTON
[nTools
]; 
 810     // this array will hold the indices of all controls in the toolbar 
 811     wxArrayInt controlIds
; 
 813     bool lastWasRadio 
= false; 
 815     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 817         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 819         // don't add separators to the vertical toolbar with old comctl32.dll 
 820         // versions as they didn't handle this properly 
 821         if ( isVertical 
&& tool
->IsSeparator() && 
 822                 wxApp::GetComCtl32Version() <= 472 ) 
 827         TBBUTTON
& button 
= buttons
[i
]; 
 829         wxZeroMemory(button
); 
 831         bool isRadio 
= false; 
 832         switch ( tool
->GetStyle() ) 
 834             case wxTOOL_STYLE_CONTROL
: 
 835                 button
.idCommand 
= tool
->GetId(); 
 836                 // fall through: create just a separator too 
 838             case wxTOOL_STYLE_SEPARATOR
: 
 839                 button
.fsState 
= TBSTATE_ENABLED
; 
 840                 button
.fsStyle 
= TBSTYLE_SEP
; 
 843             case wxTOOL_STYLE_BUTTON
: 
 844                 if ( !HasFlag(wxTB_NOICONS
) ) 
 845                     button
.iBitmap 
= bitmapId
; 
 847                 if ( HasFlag(wxTB_TEXT
) ) 
 849                     const wxString
& label 
= tool
->GetLabel(); 
 850                     if ( !label
.empty() ) 
 851                         button
.iString 
= (int)label
.c_str(); 
 854                 button
.idCommand 
= tool
->GetId(); 
 856                 if ( tool
->IsEnabled() ) 
 857                     button
.fsState 
|= TBSTATE_ENABLED
; 
 858                 if ( tool
->IsToggled() ) 
 859                     button
.fsState 
|= TBSTATE_CHECKED
; 
 861                 switch ( tool
->GetKind() ) 
 864                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 868                             // the first item in the radio group is checked by 
 869                             // default to be consistent with wxGTK and the menu 
 871                             button
.fsState 
|= TBSTATE_CHECKED
; 
 873                             if (tool
->Toggle(true)) 
 875                                 DoToggleTool(tool
, true); 
 878                         else if (tool
->IsToggled()) 
 880                             wxToolBarToolsList::compatibility_iterator nodePrev 
= node
->GetPrevious(); 
 881                             int prevIndex 
= i 
- 1; 
 884                                 TBBUTTON
& prevButton 
= buttons
[prevIndex
]; 
 885                                 wxToolBarToolBase 
*tool 
= nodePrev
->GetData(); 
 886                                 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO 
) 
 889                                 if ( tool
->Toggle(false) ) 
 890                                     DoToggleTool(tool
, false); 
 892                                 prevButton
.fsState 
= TBSTATE_ENABLED
; 
 893                                 nodePrev 
= nodePrev
->GetPrevious(); 
 902                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 906                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 910                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 911                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 919         lastWasRadio 
= isRadio
; 
 924     if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS
, (WPARAM
)i
, (LPARAM
)buttons
) ) 
 926         wxLogLastError(wxT("TB_ADDBUTTONS")); 
 931     // Deal with the controls finally 
 932     // ------------------------------ 
 934     // adjust the controls size to fit nicely in the toolbar 
 937     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext(), index
++ ) 
 939         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 941         // we calculate the running y coord for vertical toolbars so we need to 
 942         // get the items size for all items but for the horizontal ones we 
 943         // don't need to deal with the non controls 
 944         bool isControl 
= tool
->IsControl(); 
 945         if ( !isControl 
&& !isVertical 
) 
 948         // note that we use TB_GETITEMRECT and not TB_GETRECT because the 
 949         // latter only appeared in v4.70 of comctl32.dll 
 951         if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, 
 952                             index
, (LPARAM
)(LPRECT
)&r
) ) 
 954             wxLogLastError(wxT("TB_GETITEMRECT")); 
 959             // can only be control if isVertical 
 960             y 
+= r
.bottom 
- r
.top
; 
 965         wxControl 
*control 
= tool
->GetControl(); 
 966         wxSize size 
= control
->GetSize(); 
 968         // the position of the leftmost controls corner 
 969         int left 
= wxDefaultCoord
; 
 971         // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+ 
 972 #ifdef TB_SETBUTTONINFO 
 973         // available in headers, now check whether it is available now 
 975         if ( wxApp::GetComCtl32Version() >= 471 ) 
 977             // set the (underlying) separators width to be that of the 
 980             tbbi
.cbSize 
= sizeof(tbbi
); 
 981             tbbi
.dwMask 
= TBIF_SIZE
; 
 982             tbbi
.cx 
= (WORD
)size
.x
; 
 983             if ( !::SendMessage(GetHwnd(), TB_SETBUTTONINFO
, 
 984                                 tool
->GetId(), (LPARAM
)&tbbi
) ) 
 986                 // the id is probably invalid? 
 987                 wxLogLastError(wxT("TB_SETBUTTONINFO")); 
 991 #endif // comctl32.dll 4.71 
 992         // TB_SETBUTTONINFO unavailable 
 994             // try adding several separators to fit the controls width 
 995             int widthSep 
= r
.right 
- r
.left
; 
1001             tbb
.fsState 
= TBSTATE_ENABLED
; 
1002             tbb
.fsStyle 
= TBSTYLE_SEP
; 
1004             size_t nSeparators 
= size
.x 
/ widthSep
; 
1005             for ( size_t nSep 
= 0; nSep 
< nSeparators
; nSep
++ ) 
1007                 if ( !::SendMessage(GetHwnd(), TB_INSERTBUTTON
, 
1008                                     index
, (LPARAM
)&tbb
) ) 
1010                     wxLogLastError(wxT("TB_INSERTBUTTON")); 
1016             // remember the number of separators we used - we'd have to 
1017             // delete all of them later 
1018             ((wxToolBarTool 
*)tool
)->SetSeparatorsCount(nSeparators
); 
1020             // adjust the controls width to exactly cover the separators 
1021             control
->SetSize((nSeparators 
+ 1)*widthSep
, wxDefaultCoord
); 
1024         // position the control itself correctly vertically 
1025         int height 
= r
.bottom 
- r
.top
; 
1026         int diff 
= height 
- size
.y
; 
1029             // the control is too high, resize to fit 
1030             control
->SetSize(wxDefaultCoord
, height 
- 2); 
1041             y 
+= height 
+ 2 * GetMargins().y
; 
1043         else // horizontal toolbar 
1045             if ( left 
== wxDefaultCoord 
) 
1051         control
->Move(left
, top 
+ (diff 
+ 1) / 2); 
1054     // the max index is the "real" number of buttons - i.e. counting even the 
1055     // separators which we added just for aligning the controls 
1060         if ( m_maxRows 
== 0 ) 
1061             // if not set yet, only one row 
1064     else if ( m_nButtons 
> 0 ) // vertical non empty toolbar 
1066         if ( m_maxRows 
== 0 ) 
1067             // if not set yet, have one column 
1068             SetRows(m_nButtons
); 
1071     InvalidateBestSize(); 
1077 // ---------------------------------------------------------------------------- 
1079 // ---------------------------------------------------------------------------- 
1081 bool wxToolBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id
) 
1083     wxToolBarToolBase 
*tool 
= FindById((int)id
); 
1087     bool toggled 
= false; // just to suppress warnings 
1089     if ( tool
->CanBeToggled() ) 
1091         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
1092         toggled 
= (state 
& TBSTATE_CHECKED
) != 0; 
1094         // ignore the event when a radio button is released, as this doesn't 
1095         // seem to happen at all, and is handled otherwise 
1096         if ( tool
->GetKind() == wxITEM_RADIO 
&& !toggled 
) 
1099         tool
->Toggle(toggled
); 
1100         UnToggleRadioGroup(tool
); 
1103     // OnLeftClick() can veto the button state change - for buttons which 
1104     // may be toggled only, of couse 
1105     if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
1108         tool
->Toggle(!toggled
); 
1110         ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(!toggled
, 0)); 
1116 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl
), 
1118                             WXLPARAM 
*WXUNUSED(result
)) 
1120     if( !HasFlag(wxTB_NO_TOOLTIPS
) ) 
1123         // First check if this applies to us 
1124         NMHDR 
*hdr 
= (NMHDR 
*)lParam
; 
1126         // the tooltips control created by the toolbar is sometimes Unicode, even 
1127         // in an ANSI application - this seems to be a bug in comctl32.dll v5 
1128         UINT code 
= hdr
->code
; 
1129         if ( (code 
!= (UINT
) TTN_NEEDTEXTA
) && (code 
!= (UINT
) TTN_NEEDTEXTW
) ) 
1132         HWND toolTipWnd 
= (HWND
)::SendMessage(GetHwnd(), TB_GETTOOLTIPS
, 0, 0); 
1133         if ( toolTipWnd 
!= hdr
->hwndFrom 
) 
1136         LPTOOLTIPTEXT ttText 
= (LPTOOLTIPTEXT
)lParam
; 
1137         int id 
= (int)ttText
->hdr
.idFrom
; 
1139         wxToolBarToolBase 
*tool 
= FindById(id
); 
1141             return HandleTooltipNotify(code
, lParam
, tool
->GetShortHelp()); 
1143         wxUnusedVar(lParam
); 
1150 // ---------------------------------------------------------------------------- 
1152 // ---------------------------------------------------------------------------- 
1154 void wxToolBar::SetToolBitmapSize(const wxSize
& size
) 
1156     wxToolBarBase::SetToolBitmapSize(size
); 
1158     ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, MAKELONG(size
.x
, size
.y
)); 
1161 void wxToolBar::SetRows(int nRows
) 
1163     if ( nRows 
== m_maxRows 
) 
1165         // avoid resizing the frame uselessly 
1169     // TRUE in wParam means to create at least as many rows, FALSE - 
1172     ::SendMessage(GetHwnd(), TB_SETROWS
, 
1173                   MAKEWPARAM(nRows
, !(GetWindowStyle() & wxTB_VERTICAL
)), 
1181 // The button size is bigger than the bitmap size 
1182 wxSize 
wxToolBar::GetToolSize() const 
1184     // TB_GETBUTTONSIZE is supported from version 4.70 
1185 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ 
1186     && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) \ 
1187     && !defined (__DIGITALMARS__) 
1188     if ( wxApp::GetComCtl32Version() >= 470 ) 
1190         DWORD dw 
= ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE
, 0, 0); 
1192         return wxSize(LOWORD(dw
), HIWORD(dw
)); 
1195 #endif // comctl32.dll 4.70+ 
1198         return wxSize(m_defaultWidth 
+ 8, m_defaultHeight 
+ 7); 
1203 wxToolBarToolBase 
*GetItemSkippingDummySpacers(const wxToolBarToolsList
& tools
, 
1206     wxToolBarToolsList::compatibility_iterator current 
= tools
.GetFirst(); 
1208     for ( ; current 
; current 
= current
->GetNext() ) 
1211             return current
->GetData(); 
1213         wxToolBarTool 
*tool 
= (wxToolBarTool 
*)current
->GetData(); 
1214         size_t separators 
= tool
->GetSeparatorsCount(); 
1216         // if it is a normal button, sepcount == 0, so skip 1 item (the button) 
1217         // otherwise, skip as many items as the separator count, plus the 
1219         index 
-= separators 
? separators 
+ 1 : 1; 
1225 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord x
, wxCoord y
) const 
1230     int index 
= (int)::SendMessage(GetHwnd(), TB_HITTEST
, 0, (LPARAM
)&pt
); 
1232     // MBN: when the point ( x, y ) is close to the toolbar border 
1233     //      TB_HITTEST returns m_nButtons ( not -1 ) 
1234     if ( index 
< 0 || (size_t)index 
>= m_nButtons 
) 
1235         // it's a separator or there is no tool at all there 
1236         return (wxToolBarToolBase 
*)NULL
; 
1238     // when TB_SETBUTTONINFO is available (both during compile- and run-time), 
1239     // we don't use the dummy separators hack 
1240 #ifdef TB_SETBUTTONINFO 
1241     if ( wxApp::GetComCtl32Version() >= 471 ) 
1243         return m_tools
.Item((size_t)index
)->GetData(); 
1246 #endif // TB_SETBUTTONINFO 
1248         return GetItemSkippingDummySpacers( m_tools
, (size_t) index 
); 
1252 void wxToolBar::UpdateSize() 
1254     wxPoint pos 
= GetPosition(); 
1255     ::SendMessage(GetHwnd(), TB_AUTOSIZE
, 0, 0); 
1256     if (pos 
!= GetPosition()) 
1259     // In case Realize is called after the initial display (IOW the programmer 
1260     // may have rebuilt the toolbar) give the frame the option of resizing the 
1261     // toolbar to full width again, but only if the parent is a frame and the 
1262     // toolbar is managed by the frame.  Otherwise assume that some other 
1263     // layout mechanism is controlling the toolbar size and leave it alone. 
1264     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
1265     if ( frame 
&& frame
->GetToolBar() == this ) 
1267         frame
->SendSizeEvent(); 
1271 // ---------------------------------------------------------------------------- 
1273 // --------------------------------------------------------------------------- 
1275 void wxToolBar::SetWindowStyleFlag(long style
) 
1277     // the style bits whose changes force us to recreate the toolbar 
1278     static const long MASK_NEEDS_RECREATE 
= wxTB_TEXT 
| wxTB_NOICONS
; 
1280     const long styleOld 
= GetWindowStyle(); 
1282     wxToolBarBase::SetWindowStyleFlag(style
); 
1284     // don't recreate an empty toolbar: not only this is unnecessary, but it is 
1285     // also fatal as we'd then try to recreate the toolbar when it's just being 
1287     if ( GetToolsCount() && 
1288             (style 
& MASK_NEEDS_RECREATE
) != (styleOld 
& MASK_NEEDS_RECREATE
) ) 
1290         // to remove the text labels, simply re-realizing the toolbar is enough 
1291         // but I don't know of any way to add the text to an existing toolbar 
1292         // other than by recreating it entirely 
1297 // ---------------------------------------------------------------------------- 
1299 // ---------------------------------------------------------------------------- 
1301 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*tool
, bool enable
) 
1303     ::SendMessage(GetHwnd(), TB_ENABLEBUTTON
, 
1304                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(enable
, 0)); 
1307 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*tool
, bool toggle
) 
1309     ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, 
1310                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(toggle
, 0)); 
1313 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
1315     // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or 
1316     //     without, so we really need to delete the button and recreate it here 
1317     wxFAIL_MSG( _T("not implemented") ); 
1320 // ---------------------------------------------------------------------------- 
1322 // ---------------------------------------------------------------------------- 
1324 // Responds to colour changes, and passes event on to children. 
1325 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
1327     wxRGBToColour(m_backgroundColour
, ::GetSysColor(COLOR_BTNFACE
)); 
1329     // Remap the buttons 
1332     // Relayout the toolbar 
1333     int nrows 
= m_maxRows
; 
1334     m_maxRows 
= 0;      // otherwise SetRows() wouldn't do anything 
1339     // let the event propagate further 
1343 void wxToolBar::OnMouseEvent(wxMouseEvent
& event
) 
1345     if (event
.Leaving() && m_pInTool
) 
1352     if ( event
.RightDown() ) 
1354         // find the tool under the mouse 
1355         wxCoord x 
= 0, y 
= 0; 
1356         event
.GetPosition(&x
, &y
); 
1358         wxToolBarToolBase 
*tool 
= FindToolForPosition(x
, y
); 
1359         OnRightClick(tool 
? tool
->GetId() : -1, x
, y
); 
1367 // This handler is required to allow the toolbar to be set to a non-default 
1368 // colour: for example, when it must blend in with a notebook page. 
1369 void wxToolBar::OnEraseBackground(wxEraseEvent
& event
) 
1371     RECT rect 
= wxGetClientRect(GetHwnd()); 
1372     HDC hdc 
= GetHdcOf((*event
.GetDC())); 
1376         // do draw our background 
1378         // notice that this 'dumb' implementation may cause flicker for some of 
1379         // the controls in which case they should intercept wxEraseEvent and 
1380         // process it themselves somehow 
1381         AutoHBRUSH 
hBrush(wxColourToRGB(GetBackgroundColour())); 
1383         wxCHANGE_HDC_MAP_MODE(hdc
, MM_TEXT
); 
1384         ::FillRect(hdc
, &rect
, hBrush
); 
1386     else // we have no non default background colour 
1389         // we may need to draw themed colour so that we appear correctly on 
1390         // e.g. notebook page under XP with themes but only do it if the parent 
1391         // draws themed background itself 
1392         if ( !GetParent()->UseBgCol() ) 
1394             wxUxThemeEngine 
*theme 
= wxUxThemeEngine::GetIfActive(); 
1398                     hr 
= theme
->DrawThemeParentBackground(GetHwnd(), hdc
, &rect
); 
1402                 // it can also return S_FALSE which seems to simply say that it 
1403                 // didn't draw anything but no error really occurred 
1405                     wxLogApiError(_T("DrawThemeParentBackground(toolbar)"), hr
); 
1408 #endif // wxUSE_UXTHEME 
1415 bool wxToolBar::HandleSize(WXWPARAM 
WXUNUSED(wParam
), WXLPARAM lParam
) 
1417     // calculate our minor dimension ourselves - we're confusing the standard 
1418     // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks 
1420     if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT
, 0, (LPARAM
)&r
) ) 
1424         if ( GetWindowStyle() & wxTB_VERTICAL 
) 
1426             w 
= r
.right 
- r
.left
; 
1429                 w 
*= (m_nButtons 
+ m_maxRows 
- 1)/m_maxRows
; 
1436             if (HasFlag( wxTB_FLAT 
)) 
1437                 h 
= r
.bottom 
- r
.top 
- 3; 
1439                 h 
= r
.bottom 
- r
.top
; 
1442                 // FIXME: hardcoded separator line height... 
1443                 h 
+= HasFlag(wxTB_NODIVIDER
) ? 4 : 6; 
1448         if ( MAKELPARAM(w
, h
) != lParam 
) 
1450             // size really changed 
1454         // message processed 
1461 bool wxToolBar::HandlePaint(WXWPARAM wParam
, WXLPARAM lParam
) 
1463     // erase any dummy separators which were used 
1464     // for aligning the controls if any here 
1466     // first of all, are there any controls at all? 
1467     wxToolBarToolsList::compatibility_iterator node
; 
1468     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
1470         if ( node
->GetData()->IsControl() ) 
1475         // no controls, nothing to erase 
1478     // prepare the DC on which we'll be drawing 
1479     wxClientDC 
dc(this); 
1480     dc
.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID
)); 
1481     dc
.SetPen(*wxTRANSPARENT_PEN
); 
1484     if ( !::GetUpdateRect(GetHwnd(), &r
, FALSE
) ) 
1485         // nothing to redraw anyhow 
1489     wxCopyRECTToRect(r
, rectUpdate
); 
1491     dc
.SetClippingRegion(rectUpdate
); 
1493     // draw the toolbar tools, separators &c normally 
1494     wxControl::MSWWindowProc(WM_PAINT
, wParam
, lParam
); 
1496     // for each control in the toolbar find all the separators intersecting it 
1499     // NB: this is really the only way to do it as we don't know if a separator 
1500     //     corresponds to a control (i.e. is a dummy one) or a real one 
1502     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
1504         wxToolBarToolBase 
*tool 
= node
->GetData(); 
1505         if ( tool
->IsControl() ) 
1507             // get the control rect in our client coords 
1508             wxControl 
*control 
= tool
->GetControl(); 
1509             wxRect rectCtrl 
= control
->GetRect(); 
1511             // iterate over all buttons 
1513             int count 
= ::SendMessage(GetHwnd(), TB_BUTTONCOUNT
, 0, 0); 
1514             for ( int n 
= 0; n 
< count
; n
++ ) 
1516                 // is it a separator? 
1517                 if ( !::SendMessage(GetHwnd(), TB_GETBUTTON
, 
1520                     wxLogDebug(_T("TB_GETBUTTON failed?")); 
1525                 if ( tbb
.fsStyle 
!= TBSTYLE_SEP 
) 
1528                 // get the bounding rect of the separator 
1530                 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, 
1533                     wxLogDebug(_T("TB_GETITEMRECT failed?")); 
1538                 // does it intersect the control? 
1540                 wxCopyRECTToRect(r
, rectItem
); 
1541                 if ( rectCtrl
.Intersects(rectItem
) ) 
1543                     // yes, do erase it! 
1544                     dc
.DrawRectangle(rectItem
); 
1546                     // Necessary in case we use a no-paint-on-size 
1547                     // style in the parent: the controls can disappear 
1548                     control
->Refresh(false); 
1557 void wxToolBar::HandleMouseMove(WXWPARAM 
WXUNUSED(wParam
), WXLPARAM lParam
) 
1559     wxCoord x 
= GET_X_LPARAM(lParam
), 
1560             y 
= GET_Y_LPARAM(lParam
); 
1561     wxToolBarToolBase
* tool 
= FindToolForPosition( x
, y 
); 
1563     // cursor left current tool 
1564     if ( tool 
!= m_pInTool 
&& !tool 
) 
1570     // cursor entered a tool 
1571     if ( tool 
!= m_pInTool 
&& tool 
) 
1574         OnMouseEnter( tool
->GetId() ); 
1578 WXLRESULT 
wxToolBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1583             // we don't handle mouse moves, so always pass the message to 
1584             // wxControl::MSWWindowProc (HandleMouseMove just calls OnMouseEnter) 
1585             HandleMouseMove(wParam
, lParam
); 
1589             if ( HandleSize(wParam
, lParam
) ) 
1595             if ( HandlePaint(wParam
, lParam
) ) 
1603     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
1606 // ---------------------------------------------------------------------------- 
1607 // private functions 
1608 // ---------------------------------------------------------------------------- 
1610 #ifdef wxREMAP_BUTTON_COLOURS 
1612 WXHBITMAP 
wxToolBar::MapBitmap(WXHBITMAP bitmap
, int width
, int height
) 
1618         wxLogLastError(_T("CreateCompatibleDC")); 
1623     SelectInHDC 
bmpInHDC(hdcMem
, (HBITMAP
)bitmap
); 
1627         wxLogLastError(_T("SelectObject")); 
1632     wxCOLORMAP 
*cmap 
= wxGetStdColourMap(); 
1634     for ( int i 
= 0; i 
< width
; i
++ ) 
1636         for ( int j 
= 0; j 
< height
; j
++ ) 
1638             COLORREF pixel 
= ::GetPixel(hdcMem
, i
, j
); 
1640             for ( size_t k 
= 0; k 
< wxSTD_COL_MAX
; k
++ ) 
1642                 COLORREF col 
= cmap
[k
].from
; 
1643                 if ( abs(GetRValue(pixel
) - GetRValue(col
)) < 10 && 
1644                      abs(GetGValue(pixel
) - GetGValue(col
)) < 10 && 
1645                      abs(GetBValue(pixel
) - GetBValue(col
)) < 10 ) 
1647                     if ( cmap
[k
].to 
!= pixel 
) 
1648                         ::SetPixel(hdcMem
, i
, j
, cmap
[k
].to
); 
1658 #endif // wxREMAP_BUTTON_COLOURS 
1660 #endif // wxUSE_TOOLBAR