1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        msw/wince/tbarwce.cpp 
   3 // Purpose:     wxToolBar for Windows CE 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "tbarwce.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  35     #include "wx/dynarray.h" 
  36     #include "wx/settings.h" 
  37     #include "wx/bitmap.h" 
  38     #include "wx/dcmemory.h" 
  39     #include "wx/control.h" 
  42 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE 
  44 #include "wx/toolbar.h" 
  46 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__) 
  50 #include "wx/msw/private.h" 
  58 #include "wx/msw/winundef.h" 
  60 #if defined(__MWERKS__) && defined(__WXMSW__) 
  61 // including <windef.h> for max definition doesn't seem 
  62 // to work using CodeWarrior 6 Windows. So we define it 
  63 // here. (Otherwise we get a undefined identifier 'max' 
  64 // later on in this file.) (Added by dimitri@shortcut.nl) 
  66 #       define max(a,b)            (((a) > (b)) ? (a) : (b)) 
  71 // ---------------------------------------------------------------------------- 
  72 // conditional compilation 
  73 // ---------------------------------------------------------------------------- 
  75 // wxWindows previously always considered that toolbar buttons have light grey 
  76 // (0xc0c0c0) background and so ignored any bitmap masks - however, this 
  77 // doesn't work with XPMs which then appear to have black background. To make 
  78 // this work, we must respect the bitmap masks - which we do now. This should 
  79 // be ok in any case, but to restore 100% compatible with the old version 
  80 // behaviour, you can set this to 0. 
  81 #define USE_BITMAP_MASKS 1 
  83 // ---------------------------------------------------------------------------- 
  85 // ---------------------------------------------------------------------------- 
  87 // these standard constants are not always defined in compilers headers 
  91     #define TBSTYLE_LIST            0x1000 
  92     #define TBSTYLE_FLAT            0x0800 
  95 #ifndef TBSTYLE_TRANSPARENT 
  96     #define TBSTYLE_TRANSPARENT     0x8000 
  99 #ifndef TBSTYLE_TOOLTIPS 
 100     #define TBSTYLE_TOOLTIPS        0x0100 
 105     #define TB_SETSTYLE             (WM_USER + 56) 
 106     #define TB_GETSTYLE             (WM_USER + 57) 
 110     #define TB_HITTEST              (WM_USER + 69) 
 113 // these values correspond to those used by comctl32.dll 
 114 #define DEFAULTBITMAPX   16 
 115 #define DEFAULTBITMAPY   15 
 116 #define DEFAULTBUTTONX   24 
 117 #define DEFAULTBUTTONY   24 
 118 #define DEFAULTBARHEIGHT 27 
 120 // ---------------------------------------------------------------------------- 
 122 // ---------------------------------------------------------------------------- 
 124 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
) 
 126 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 127     EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent
) 
 128     EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged
) 
 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
; } 
 182 // ============================================================================ 
 184 // ============================================================================ 
 186 // ---------------------------------------------------------------------------- 
 188 // ---------------------------------------------------------------------------- 
 190 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 191                                          const wxString
& label
, 
 192                                          const wxBitmap
& bmpNormal
, 
 193                                          const wxBitmap
& bmpDisabled
, 
 195                                          wxObject 
*clientData
, 
 196                                          const wxString
& shortHelp
, 
 197                                          const wxString
& longHelp
) 
 199     return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 200                              clientData
, shortHelp
, longHelp
); 
 203 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 205     return new wxToolBarTool(this, control
); 
 208 // ---------------------------------------------------------------------------- 
 209 // wxToolBar construction 
 210 // ---------------------------------------------------------------------------- 
 212 void wxToolBar::Init() 
 218     m_defaultWidth 
= DEFAULTBITMAPX
; 
 219     m_defaultHeight 
= DEFAULTBITMAPY
; 
 225 bool wxToolBar::Create(wxWindow 
*parent
, 
 230                        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
, menuBar
) ) 
 241     // set up the colors and fonts 
 242     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR
)); 
 243     SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 248 #ifndef TBSTYLE_NO_DROPDOWN_ARROW 
 249 #define TBSTYLE_NO_DROPDOWN_ARROW 0x0080 
 252 bool wxToolBar::MSWCreateToolbar(const wxPoint
& pos
, const wxSize
& size
, wxMenuBar
* menuBar
) 
 256         m_menuBar
->SetToolBar(this); 
 258     // Create the menubar. 
 261     memset (&mbi
, 0, sizeof (SHMENUBARINFO
)); 
 262     mbi
.cbSize     
= sizeof (SHMENUBARINFO
); 
 263     mbi
.hwndParent 
= (HWND
) GetParent()->GetHWND(); 
 265     mbi
.nToolBarId 
= 5002; 
 267     mbi
.nToolBarId 
= 5000; 
 271     mbi
.dwFlags 
= 0 ; // SHCMBF_EMPTYBAR; 
 272     mbi
.hInstRes 
= wxGetInstance(); 
 274     if (!SHCreateMenuBar(&mbi
)) 
 276         wxFAIL_MSG( _T("SHCreateMenuBar failed") ); 
 280     SetHWND((WXHWND
) mbi
.hwndMB
); 
 282     if (!::SendMessage((HWND) GetHWND(), TB_DELETEBUTTON, 0, (LPARAM) 0)) 
 284         wxLogLastError(wxT("TB_DELETEBUTTON")); 
 287     // install wxWindows window proc for this window 
 296 void wxToolBar::Recreate() 
 299     const HWND hwndOld 
= GetHwnd(); 
 302         // we haven't been created yet, no need to recreate 
 306     // get the position and size before unsubclassing the old toolbar 
 307     const wxPoint pos 
= GetPosition(); 
 308     const wxSize size 
= GetSize(); 
 312     if ( !MSWCreateToolbar(pos
, size
) ) 
 315         wxFAIL_MSG( _T("recreating the toolbar failed") ); 
 320     // reparent all our children under the new toolbar 
 321     for ( wxWindowList::compatibility_iterator node 
= m_children
.GetFirst(); 
 323           node 
= node
->GetNext() ) 
 325         wxWindow 
*win 
= node
->GetData(); 
 326         if ( !win
->IsTopLevel() ) 
 327             ::SetParent(GetHwndOf(win
), GetHwnd()); 
 330     // only destroy the old toolbar now -- after all the children had been 
 332     ::DestroyWindow(hwndOld
); 
 334     // it is for the old bitmap control and can't be used with the new one 
 337         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 346 wxToolBar::~wxToolBar() 
 349         GetMenuBar()->SetToolBar(NULL
); 
 351     // we must refresh the frame size when the toolbar is deleted but the frame 
 352     // is not - otherwise toolbar leaves a hole in the place it used to occupy 
 353     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
 354     if ( frame 
&& !frame
->IsBeingDeleted() ) 
 356         frame
->SendSizeEvent(); 
 361         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 365 wxSize 
wxToolBar::DoGetBestSize() const 
 367     wxSize sizeBest 
= GetToolSize(); 
 368     sizeBest
.x 
*= GetToolsCount(); 
 370     // reverse horz and vertical components if necessary 
 371     return HasFlag(wxTB_VERTICAL
) ? wxSize(sizeBest
.y
, sizeBest
.x
) : sizeBest
; 
 374 // Return HMENU for the menu associated with the commandbar 
 375 WXHMENU 
wxToolBar::GetHMenu() 
 379         return (WXHMENU
) (HMENU
)::SendMessage((HWND
) GetHWND(), SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0); 
 386 WXDWORD 
wxToolBar::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 388     // toolbars never have border, giving one to them results in broken 
 390     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 392                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 395     // always include this one, it never hurts and setting it later only if we 
 396     // do have tooltips wouldn't work 
 397     msStyle 
|= TBSTYLE_TOOLTIPS
; 
 399     if ( style 
& (wxTB_FLAT 
| wxTB_HORZ_LAYOUT
) ) 
 401         // static as it doesn't change during the program lifetime 
 402         static int s_verComCtl 
= wxTheApp
->GetComCtl32Version(); 
 404         // comctl32.dll 4.00 doesn't support the flat toolbars and using this 
 405         // style with 6.00 (part of Windows XP) leads to the toolbar with 
 406         // incorrect background colour - and not using it still results in the 
 407         // correct (flat) toolbar, so don't use it there 
 408         if ( s_verComCtl 
> 400 && s_verComCtl 
< 600 ) 
 410             msStyle 
|= TBSTYLE_FLAT 
| TBSTYLE_TRANSPARENT
; 
 413         if ( s_verComCtl 
>= 470 && style 
& wxTB_HORZ_LAYOUT 
) 
 415             msStyle 
|= TBSTYLE_LIST
; 
 419     if ( style 
& wxTB_NODIVIDER 
) 
 420         msStyle 
|= CCS_NODIVIDER
; 
 422     if ( style 
& wxTB_NOALIGN 
) 
 423         msStyle 
|= CCS_NOPARENTALIGN
; 
 425     if ( style 
& wxTB_VERTICAL 
) 
 431 // ---------------------------------------------------------------------------- 
 432 // adding/removing tools 
 433 // ---------------------------------------------------------------------------- 
 435 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 437     // nothing special to do here - we really create the toolbar buttons in 
 444 bool wxToolBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 446     // the main difficulty we have here is with the controls in the toolbars: 
 447     // as we (sometimes) use several separators to cover up the space used by 
 448     // them, the indices are not the same for us and the toolbar 
 450     // first determine the position of the first button to delete: it may be 
 451     // different from pos if we use several separators to cover the space used 
 453     wxToolBarToolsList::compatibility_iterator node
; 
 454     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 456         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 459             // let node point to the next node in the list 
 460             node 
= node
->GetNext(); 
 465         if ( tool2
->IsControl() ) 
 467             pos 
+= ((wxToolBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 471     // now determine the number of buttons to delete and the area taken by them 
 472     size_t nButtonsToDelete 
= 1; 
 474     // get the size of the button we're going to delete 
 476     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 478         wxLogLastError(_T("TB_GETITEMRECT")); 
 481     int width 
= r
.right 
- r
.left
; 
 483     if ( tool
->IsControl() ) 
 485         nButtonsToDelete 
= ((wxToolBarTool 
*)tool
)->GetSeparatorsCount(); 
 487         width 
*= nButtonsToDelete
; 
 490     // do delete all buttons 
 491     m_nButtons 
-= nButtonsToDelete
; 
 492     while ( nButtonsToDelete
-- > 0 ) 
 494         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 496             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 504     // and finally reposition all the controls after this button (the toolbar 
 505     // takes care of all normal items) 
 506     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 508         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 509         if ( tool2
->IsControl() ) 
 512             wxControl 
*control 
= tool2
->GetControl(); 
 513             control
->GetPosition(&x
, NULL
); 
 514             control
->Move(x 
- width
, -1); 
 521 struct wxToolBarIdMapping
 
 527 static wxToolBarIdMapping sm_ToolBarIdMappingArray
[] = 
 529     { wxID_COPY
, STD_COPY 
}, 
 530     { wxID_CUT
, STD_CUT 
}, 
 531     { wxID_FIND
, STD_FIND 
}, 
 532     { wxID_PASTE
, STD_PASTE 
}, 
 533     { wxID_NEW
, STD_FILENEW 
}, 
 534     { wxID_OPEN
, STD_FILEOPEN 
}, 
 535     { wxID_SAVE
, STD_FILESAVE 
}, 
 536     { wxID_PRINT
, STD_PRINT 
}, 
 537     { wxID_PREVIEW
, STD_PRINTPRE 
}, 
 538     { wxID_UNDO
, STD_UNDO  
}, 
 539     { wxID_REDO
, STD_REDOW 
}, 
 540     { wxID_HELP
, STD_HELP 
}, 
 541     { wxID_DELETE
, STD_DELETE 
}, 
 542     { wxID_REPLACE
, STD_REPLACE 
}, 
 543     { wxID_PROPERTIES
, STD_PROPERTIES 
}, 
 544     { wxID_VIEW_DETAILS
, VIEW_DETAILS 
}, 
 545     { wxID_VIEW_SORTDATE
, VIEW_SORTDATE 
}, 
 546     { wxID_VIEW_LARGEICONS
, VIEW_LARGEICONS 
}, 
 547     { wxID_VIEW_SORTNAME
, VIEW_SORTNAME 
}, 
 548     { wxID_VIEW_LIST
, VIEW_LIST 
}, 
 549     { wxID_VIEW_SORTSIZE
, VIEW_SORTSIZE 
}, 
 550     { wxID_VIEW_SMALLICONS
, VIEW_SMALLICONS 
}, 
 551     { wxID_VIEW_SORTTYPE
, VIEW_SORTTYPE 
}, 
 555 static int wxFindIdForWinceId(int id
) 
 560         if (sm_ToolBarIdMappingArray
[i
].m_winceId 
== 0) 
 562         else if (sm_ToolBarIdMappingArray
[i
].m_winceId 
== id
) 
 563             return sm_ToolBarIdMappingArray
[i
].m_wxwinId
; 
 569 static int wxFindIdForwxWinId(int id
) 
 574         if (sm_ToolBarIdMappingArray
[i
].m_wxwinId 
== 0) 
 576         else if (sm_ToolBarIdMappingArray
[i
].m_wxwinId 
== id
) 
 577             return sm_ToolBarIdMappingArray
[i
].m_winceId
; 
 584 bool wxToolBar::Realize() 
 586     const size_t nTools 
= GetToolsCount(); 
 593     const bool isVertical 
= HasFlag(wxTB_VERTICAL
); 
 596     // delete all old buttons, if any 
 597     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 599         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 601             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 606     // add the buttons and separators 
 607     // ------------------------------ 
 609     // Use standard buttons 
 610     CommandBar_AddBitmap((HWND
) GetHWND(), HINST_COMMCTRL
, 
 611         IDB_STD_SMALL_COLOR
, 0, 16, 16); 
 613     TBBUTTON 
*buttons 
= new TBBUTTON
[nTools
]; 
 615     // this array will hold the indices of all controls in the toolbar 
 616     wxArrayInt controlIds
; 
 618     bool lastWasRadio 
= FALSE
; 
 620     wxToolBarToolsList::Node
* node
; 
 621     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 623         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 625         bool processedThis 
= TRUE
; 
 627         TBBUTTON
& button 
= buttons
[i
]; 
 629         wxZeroMemory(button
); 
 631         bool isRadio 
= FALSE
; 
 632         switch ( tool
->GetStyle() ) 
 634             case wxTOOL_STYLE_CONTROL
: 
 635                 button
.idCommand 
= tool
->GetId(); 
 636                 // fall through: create just a separator too 
 638             case wxTOOL_STYLE_SEPARATOR
: 
 639                 button
.fsState 
= TBSTATE_ENABLED
; 
 640                 button
.fsStyle 
= TBSTYLE_SEP
; 
 643             case wxTOOL_STYLE_BUTTON
: 
 644 //                if ( !HasFlag(wxTB_NOICONS) ) 
 645 //                    button.iBitmap = bitmapId; 
 647                 if ( HasFlag(wxTB_TEXT
) ) 
 649                     const wxString
& label 
= tool
->GetLabel(); 
 650                     if ( !label
.empty() ) 
 652                         button
.iString 
= (int)label
.c_str(); 
 656                 int winceId 
= wxFindIdForwxWinId(tool
->GetId()); 
 659                     button
.idCommand 
= tool
->GetId(); 
 660 //                if ( !HasFlag(wxTB_NOICONS) ) 
 661                     button
.iBitmap 
= winceId
; 
 664                     processedThis 
= FALSE
; 
 666                 if ( tool
->IsEnabled() ) 
 667                     button
.fsState 
|= TBSTATE_ENABLED
; 
 668                 if ( tool
->IsToggled() ) 
 669                     button
.fsState 
|= TBSTATE_CHECKED
; 
 671                 switch ( tool
->GetKind() ) 
 674                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 678                             // the first item in the radio group is checked by 
 679                             // default to be consistent with wxGTK and the menu 
 681                             button
.fsState 
|= TBSTATE_CHECKED
; 
 690                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 694                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 698                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 705         lastWasRadio 
= isRadio
; 
 711     // Add buttons to Commandbar 
 712     if (!CommandBar_AddButtons(GetHwnd(), i
, buttons
)) 
 714         wxLogLastError(wxT("CommandBar_AddButtons")); 
 720     // Deal with the controls finally 
 721     // ------------------------------ 
 723     // adjust the controls size to fit nicely in the toolbar 
 726     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext(), index
++ ) 
 728         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 730         // we calculate the running y coord for vertical toolbars so we need to 
 731         // get the items size for all items but for the horizontal ones we 
 732         // don't need to deal with the non controls 
 733         bool isControl 
= tool
->IsControl(); 
 734         if ( !isControl 
&& !isVertical 
) 
 737         // note that we use TB_GETITEMRECT and not TB_GETRECT because the 
 738         // latter only appeared in v4.70 of comctl32.dll 
 740         if ( !SendMessage(GetHwnd(), TB_GETITEMRECT
, 
 741                           index
, (LPARAM
)(LPRECT
)&r
) ) 
 743             wxLogLastError(wxT("TB_GETITEMRECT")); 
 748             // can only be control if isVertical 
 749             y 
+= r
.bottom 
- r
.top
; 
 754         wxControl 
*control 
= tool
->GetControl(); 
 756         wxSize size 
= control
->GetSize(); 
 758         // the position of the leftmost controls corner 
 761         // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+ 
 762 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) 
 763         // available in headers, now check whether it is available now 
 765         if ( wxTheApp
->GetComCtl32Version() >= 471 ) 
 767             // set the (underlying) separators width to be that of the 
 770             tbbi
.cbSize 
= sizeof(tbbi
); 
 771             tbbi
.dwMask 
= TBIF_SIZE
; 
 773             if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO
, 
 774                               tool
->GetId(), (LPARAM
)&tbbi
) ) 
 776                 // the id is probably invalid? 
 777                 wxLogLastError(wxT("TB_SETBUTTONINFO")); 
 781 #endif // comctl32.dll 4.71 
 782         // TB_SETBUTTONINFO unavailable 
 784             // try adding several separators to fit the controls width 
 785             int widthSep 
= r
.right 
- r
.left
; 
 791             tbb
.fsState 
= TBSTATE_ENABLED
; 
 792             tbb
.fsStyle 
= TBSTYLE_SEP
; 
 794             size_t nSeparators 
= size
.x 
/ widthSep
; 
 795             for ( size_t nSep 
= 0; nSep 
< nSeparators
; nSep
++ ) 
 797                 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON
, 
 798                                   index
, (LPARAM
)&tbb
) ) 
 800                     wxLogLastError(wxT("TB_INSERTBUTTON")); 
 806             // remember the number of separators we used - we'd have to 
 807             // delete all of them later 
 808             ((wxToolBarTool 
*)tool
)->SetSeparatorsCount(nSeparators
); 
 810             // adjust the controls width to exactly cover the separators 
 811             control
->SetSize((nSeparators 
+ 1)*widthSep
, -1); 
 814         // position the control itself correctly vertically 
 815         int height 
= r
.bottom 
- r
.top
; 
 816         int diff 
= height 
- size
.y
; 
 819             // the control is too high, resize to fit 
 820             control
->SetSize(-1, height 
- 2); 
 831             y 
+= height 
+ 2*GetMargins().y
; 
 833         else // horizontal toolbar 
 841         control
->Move(left
, top 
+ (diff 
+ 1) / 2); 
 844     // the max index is the "real" number of buttons - i.e. counting even the 
 845     // separators which we added just for aligning the controls 
 850         if ( m_maxRows 
== 0 ) 
 852             // if not set yet, only one row 
 856     else if ( m_nButtons 
> 0 ) // vertical non empty toolbar 
 858         if ( m_maxRows 
== 0 ) 
 860             // if not set yet, have one column 
 869 // ---------------------------------------------------------------------------- 
 871 // ---------------------------------------------------------------------------- 
 873 bool wxToolBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id
) 
 875     wxToolBarToolBase 
*tool 
= FindById((int)id
); 
 878         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
); 
 879         event
.SetEventObject(this); 
 883         return GetEventHandler()->ProcessEvent(event
); 
 886     if ( tool
->CanBeToggled() ) 
 888         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
 889         tool
->Toggle((state 
& TBSTATE_CHECKED
) != 0); 
 892     bool toggled 
= tool
->IsToggled(); 
 894     // avoid sending the event when a radio button is released, this is not 
 896     if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO 
|| toggled 
) 
 898         // OnLeftClick() can veto the button state change - for buttons which 
 899         // may be toggled only, of couse 
 900         if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
 904             tool
->SetToggle(toggled
); 
 906             ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0)); 
 913 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl
), 
 915                             WXLPARAM 
*WXUNUSED(result
)) 
 918     // First check if this applies to us 
 919     NMHDR 
*hdr 
= (NMHDR 
*)lParam
; 
 921     // the tooltips control created by the toolbar is sometimes Unicode, even 
 922     // in an ANSI application - this seems to be a bug in comctl32.dll v5 
 923     UINT code 
= hdr
->code
; 
 924     if ( (code 
!= (UINT
) TTN_NEEDTEXTA
) && (code 
!= (UINT
) TTN_NEEDTEXTW
) ) 
 927     HWND toolTipWnd 
= (HWND
)::SendMessage((HWND
)GetHWND(), TB_GETTOOLTIPS
, 0, 0); 
 928     if ( toolTipWnd 
!= hdr
->hwndFrom 
) 
 931     LPTOOLTIPTEXT ttText 
= (LPTOOLTIPTEXT
)lParam
; 
 932     int id 
= (int)ttText
->hdr
.idFrom
; 
 934     wxToolBarToolBase 
*tool 
= FindById(id
); 
 938     return HandleTooltipNotify(code
, lParam
, tool
->GetShortHelp()); 
 944 // ---------------------------------------------------------------------------- 
 946 // ---------------------------------------------------------------------------- 
 948 void wxToolBar::SetToolBitmapSize(const wxSize
& size
) 
 950     wxToolBarBase::SetToolBitmapSize(size
); 
 952     ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, MAKELONG(size
.x
, size
.y
)); 
 955 void wxToolBar::SetRows(int nRows
) 
 957     if ( nRows 
== m_maxRows 
) 
 959         // avoid resizing the frame uselessly 
 963     // TRUE in wParam means to create at least as many rows, FALSE - 
 966     ::SendMessage(GetHwnd(), TB_SETROWS
, 
 967                   MAKEWPARAM(nRows
, !(GetWindowStyle() & wxTB_VERTICAL
)), 
 975 // The button size is bigger than the bitmap size 
 976 wxSize 
wxToolBar::GetToolSize() const 
 978     // TB_GETBUTTONSIZE is supported from version 4.70 
 979 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ 
 980     && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) 
 981     if ( wxTheApp
->GetComCtl32Version() >= 470 ) 
 983         DWORD dw 
= ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE
, 0, 0); 
 985         return wxSize(LOWORD(dw
), HIWORD(dw
)); 
 988 #endif // comctl32.dll 4.70+ 
 991         return wxSize(m_defaultWidth 
+ 8, m_defaultHeight 
+ 7); 
 996 wxToolBarToolBase 
*GetItemSkippingDummySpacers(const wxToolBarToolsList
& tools
, 
 999     wxToolBarToolsList::compatibility_iterator current 
= tools
.GetFirst(); 
1001     for ( ; current 
!= 0; current 
= current
->GetNext() ) 
1004             return current
->GetData(); 
1006         wxToolBarTool 
*tool 
= (wxToolBarTool 
*)current
->GetData(); 
1007         size_t separators 
= tool
->GetSeparatorsCount(); 
1009         // if it is a normal button, sepcount == 0, so skip 1 item (the button) 
1010         // otherwise, skip as many items as the separator count, plus the 
1012         index 
-= separators 
? separators 
+ 1 : 1; 
1018 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord x
, wxCoord y
) const 
1023     int index 
= (int)::SendMessage(GetHwnd(), TB_HITTEST
, 0, (LPARAM
)&pt
); 
1024     // MBN: when the point ( x, y ) is close to the toolbar border 
1025     //      TB_HITTEST returns m_nButtons ( not -1 ) 
1026     if ( index 
< 0 || (size_t)index 
>= m_nButtons 
) 
1028         // it's a separator or there is no tool at all there 
1029         return (wxToolBarToolBase 
*)NULL
; 
1032     // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers 
1033 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) 
1034     if ( wxTheApp
->GetComCtl32Version() >= 471 ) 
1036         return m_tools
.Item((size_t)index
)->GetData(); 
1041         return GetItemSkippingDummySpacers( m_tools
, (size_t) index 
); 
1045 void wxToolBar::UpdateSize() 
1047     // the toolbar size changed 
1048     SendMessage(GetHwnd(), TB_AUTOSIZE
, 0, 0); 
1050     // we must also refresh the frame after the toolbar size (possibly) changed 
1051     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
1054         frame
->SendSizeEvent(); 
1058 // ---------------------------------------------------------------------------- 
1060 // --------------------------------------------------------------------------- 
1062 void wxToolBar::SetWindowStyleFlag(long style
) 
1064     // the style bits whose changes force us to recreate the toolbar 
1065     static const long MASK_NEEDS_RECREATE 
= wxTB_TEXT 
| wxTB_NOICONS
; 
1067     const long styleOld 
= GetWindowStyle(); 
1069     wxToolBarBase::SetWindowStyleFlag(style
); 
1071     // don't recreate an empty toolbar: not only this is unnecessary, but it is 
1072     // also fatal as we'd then try to recreate the toolbar when it's just being 
1074     if ( GetToolsCount() && 
1075             (style 
& MASK_NEEDS_RECREATE
) != (styleOld 
& MASK_NEEDS_RECREATE
) ) 
1077         // to remove the text labels, simply re-realizing the toolbar is enough 
1078         // but I don't know of any way to add the text to an existing toolbar 
1079         // other than by recreating it entirely 
1084 // ---------------------------------------------------------------------------- 
1086 // ---------------------------------------------------------------------------- 
1088 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*tool
, bool enable
) 
1090     ::SendMessage(GetHwnd(), TB_ENABLEBUTTON
, 
1091                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(enable
, 0)); 
1094 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*tool
, bool toggle
) 
1096     ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, 
1097                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(toggle
, 0)); 
1100 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
1102     // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or 
1103     //     without, so we really need to delete the button and recreate it here 
1104     wxFAIL_MSG( _T("not implemented") ); 
1107 // ---------------------------------------------------------------------------- 
1109 // ---------------------------------------------------------------------------- 
1111 // Responds to colour changes, and passes event on to children. 
1112 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
1114     wxRGBToColour(m_backgroundColour
, ::GetSysColor(COLOR_BTNFACE
)); 
1116     // Remap the buttons 
1119     // Relayout the toolbar 
1120     int nrows 
= m_maxRows
; 
1121     m_maxRows 
= 0;      // otherwise SetRows() wouldn't do anything 
1126     // let the event propagate further 
1130 void wxToolBar::OnMouseEvent(wxMouseEvent
& event
) 
1132     if (event
.Leaving() && m_pInTool
) 
1139     if (event
.RightDown()) 
1141         // For now, we don't have an id. Later we could 
1142         // try finding the tool. 
1143         OnRightClick((int)-1, event
.GetX(), event
.GetY()); 
1151 void wxToolBar::HandleMouseMove(WXWPARAM wParam
, WXLPARAM lParam
) 
1153     wxCoord x 
= GET_X_LPARAM(lParam
), 
1154             y 
= GET_Y_LPARAM(lParam
); 
1155     wxToolBarToolBase
* tool 
= FindToolForPosition( x
, y 
); 
1157     // cursor left current tool 
1158     if( tool 
!= m_pInTool 
&& !tool 
) 
1164     // cursor entered a tool 
1165     if( tool 
!= m_pInTool 
&& tool 
) 
1168         OnMouseEnter( tool
->GetId() ); 
1172 long wxToolBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1178             if ( HandleSize(wParam
, lParam
) ) 
1183             // we don't handle mouse moves, so always pass the message to 
1184             // wxControl::MSWWindowProc 
1185             HandleMouseMove(wParam
, lParam
); 
1189     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
1192 // ---------------------------------------------------------------------------- 
1193 // private functions 
1194 // ---------------------------------------------------------------------------- 
1196 WXHBITMAP 
wxToolBar::MapBitmap(WXHBITMAP bitmap
, int width
, int height
) 
1202         wxLogLastError(_T("CreateCompatibleDC")); 
1207     SelectInHDC 
bmpInHDC(hdcMem
, (HBITMAP
)bitmap
); 
1211         wxLogLastError(_T("SelectObject")); 
1216     wxCOLORMAP 
*cmap 
= wxGetStdColourMap(); 
1218     for ( int i 
= 0; i 
< width
; i
++ ) 
1220         for ( int j 
= 0; j 
< height
; j
++ ) 
1222             COLORREF pixel 
= ::GetPixel(hdcMem
, i
, j
); 
1224             for ( size_t k 
= 0; k 
< wxSTD_COL_MAX
; k
++ ) 
1226                 COLORREF col 
= cmap
[k
].from
; 
1227                 if ( abs(GetRValue(pixel
) - GetRValue(col
)) < 10 && 
1228                      abs(GetGValue(pixel
) - GetGValue(col
)) < 10 && 
1229                      abs(GetBValue(pixel
) - GetBValue(col
)) < 10 ) 
1231                     ::SetPixel(hdcMem
, i
, j
, cmap
[k
].to
); 
1240     // VZ: I leave here my attempts to map the bitmap to the system colours 
1241     //     faster by using BitBlt() even though it's broken currently - but 
1242     //     maybe someone else can finish it? It should be faster than iterating 
1243     //     over all pixels... 
1245     MemoryHDC hdcMask
, hdcDst
; 
1246     if ( !hdcMask 
|| !hdcDst 
) 
1248         wxLogLastError(_T("CreateCompatibleDC")); 
1253     // create the target bitmap 
1254     HBITMAP hbmpDst 
= ::CreateCompatibleBitmap(hdcDst
, width
, height
); 
1257         wxLogLastError(_T("CreateCompatibleBitmap")); 
1262     // create the monochrome mask bitmap 
1263     HBITMAP hbmpMask 
= ::CreateBitmap(width
, height
, 1, 1, 0); 
1266         wxLogLastError(_T("CreateBitmap(mono)")); 
1268         ::DeleteObject(hbmpDst
); 
1273     SelectInHDC 
bmpInDst(hdcDst
, hbmpDst
), 
1274                 bmpInMask(hdcMask
, hbmpMask
); 
1277     for ( n 
= 0; n 
< NUM_OF_MAPPED_COLOURS
; n
++ ) 
1279         // create the mask for this colour 
1280         ::SetBkColor(hdcMem
, ColorMap
[n
].from
); 
1281         ::BitBlt(hdcMask
, 0, 0, width
, height
, hdcMem
, 0, 0, SRCCOPY
); 
1283         // replace this colour with the target one in the dst bitmap 
1284         HBRUSH hbr 
= ::CreateSolidBrush(ColorMap
[n
].to
); 
1285         HGDIOBJ hbrOld 
= ::SelectObject(hdcDst
, hbr
); 
1287         ::MaskBlt(hdcDst
, 0, 0, width
, height
, 
1290                   MAKEROP4(PATCOPY
, SRCCOPY
)); 
1292         (void)::SelectObject(hdcDst
, hbrOld
); 
1293         ::DeleteObject(hbr
); 
1296     ::DeleteObject((HBITMAP
)bitmap
); 
1298     return (WXHBITMAP
)hbmpDst
; 
1302 #endif // wxUSE_TOOLBAR && Win95