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 // Use the WinCE-specific toolbar only if we're either compiling 
  43 // with a WinCE earlier than 4, or we wish to emulate a PocketPC-style UI 
  44 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (_WIN32_WCE < 400 || defined(__POCKETPC__) || defined(__SMARTPHONE__)) 
  46 #include "wx/toolbar.h" 
  48 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__) 
  52 #include "wx/msw/private.h" 
  59 #if defined(WINCE_WITHOUT_COMMANDBAR) 
  62 #include "wx/msw/wince/missing.h" 
  64 #include "wx/msw/winundef.h" 
  66 #if defined(__MWERKS__) && defined(__WXMSW__) 
  67 // including <windef.h> for max definition doesn't seem 
  68 // to work using CodeWarrior 6 Windows. So we define it 
  69 // here. (Otherwise we get a undefined identifier 'max' 
  70 // later on in this file.) (Added by dimitri@shortcut.nl) 
  72 #       define max(a,b)            (((a) > (b)) ? (a) : (b)) 
  77 // ---------------------------------------------------------------------------- 
  79 // ---------------------------------------------------------------------------- 
  81 // these standard constants are not always defined in compilers headers 
  85     #define TBSTYLE_LIST            0x1000 
  86     #define TBSTYLE_FLAT            0x0800 
  89 #ifndef TBSTYLE_TRANSPARENT 
  90     #define TBSTYLE_TRANSPARENT     0x8000 
  93 #ifndef TBSTYLE_TOOLTIPS 
  94     #define TBSTYLE_TOOLTIPS        0x0100 
  99     #define TB_SETSTYLE             (WM_USER + 56) 
 100     #define TB_GETSTYLE             (WM_USER + 57) 
 104     #define TB_HITTEST              (WM_USER + 69) 
 107 // these values correspond to those used by comctl32.dll 
 108 #define DEFAULTBITMAPX   16 
 109 #define DEFAULTBITMAPY   15 
 110 #define DEFAULTBUTTONX   24 
 111 #define DEFAULTBUTTONY   24 
 112 #define DEFAULTBARHEIGHT 27 
 114 // ---------------------------------------------------------------------------- 
 116 // ---------------------------------------------------------------------------- 
 118 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxControl
) 
 120 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 121     EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent
) 
 122     EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged
) 
 125 // ---------------------------------------------------------------------------- 
 127 // ---------------------------------------------------------------------------- 
 129 class wxToolBarTool 
: public wxToolBarToolBase
 
 132     wxToolBarTool(wxToolBar 
*tbar
, 
 134                   const wxString
& label
, 
 135                   const wxBitmap
& bmpNormal
, 
 136                   const wxBitmap
& bmpDisabled
, 
 138                   wxObject 
*clientData
, 
 139                   const wxString
& shortHelp
, 
 140                   const wxString
& longHelp
) 
 141         : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 142                             clientData
, shortHelp
, longHelp
) 
 147     wxToolBarTool(wxToolBar 
*tbar
, wxControl 
*control
) 
 148         : wxToolBarToolBase(tbar
, control
) 
 153     virtual void SetLabel(const wxString
& label
) 
 155         if ( label 
== m_label 
) 
 158         wxToolBarToolBase::SetLabel(label
); 
 160         // we need to update the label shown in the toolbar because it has a 
 161         // pointer to the internal buffer of the old label 
 163         // TODO: use TB_SETBUTTONINFO 
 166     // set/get the number of separators which we use to cover the space used by 
 167     // a control in the toolbar 
 168     void SetSeparatorsCount(size_t count
) { m_nSepCount 
= count
; } 
 169     size_t GetSeparatorsCount() const { return m_nSepCount
; } 
 176 // ============================================================================ 
 178 // ============================================================================ 
 180 // ---------------------------------------------------------------------------- 
 182 // ---------------------------------------------------------------------------- 
 184 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 185                                          const wxString
& label
, 
 186                                          const wxBitmap
& bmpNormal
, 
 187                                          const wxBitmap
& bmpDisabled
, 
 189                                          wxObject 
*clientData
, 
 190                                          const wxString
& shortHelp
, 
 191                                          const wxString
& longHelp
) 
 193     return new wxToolBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 194                              clientData
, shortHelp
, longHelp
); 
 197 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 199     return new wxToolBarTool(this, control
); 
 202 // ---------------------------------------------------------------------------- 
 203 // wxToolBar construction 
 204 // ---------------------------------------------------------------------------- 
 206 void wxToolBar::Init() 
 212     m_defaultWidth 
= DEFAULTBITMAPX
; 
 213     m_defaultHeight 
= DEFAULTBITMAPY
; 
 219 bool wxToolBar::Create(wxWindow 
*parent
, 
 224                        const wxString
& name
, 
 227     // common initialisation 
 228     if ( !CreateControl(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) ) 
 231     // MSW-specific initialisation 
 232     if ( !MSWCreateToolbar(pos
, size
, menuBar
) ) 
 235     // set up the colors and fonts 
 236     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR
)); 
 237     SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 242 #ifndef TBSTYLE_NO_DROPDOWN_ARROW 
 243 #define TBSTYLE_NO_DROPDOWN_ARROW 0x0080 
 246 bool wxToolBar::MSWCreateToolbar(const wxPoint
& WXUNUSED(pos
), const wxSize
& WXUNUSED(size
), wxMenuBar
* menuBar
) 
 250         m_menuBar
->SetToolBar(this); 
 252 #if defined(WINCE_WITHOUT_COMMANDBAR) 
 253     // Create the menubar. 
 256     memset (&mbi
, 0, sizeof (SHMENUBARINFO
)); 
 257     mbi
.cbSize     
= sizeof (SHMENUBARINFO
); 
 258     mbi
.hwndParent 
= (HWND
) GetParent()->GetHWND(); 
 259 #ifdef __SMARTPHONE__ 
 260     mbi
.nToolBarId 
= 5002; 
 262     mbi
.nToolBarId 
= 5000; 
 266     mbi
.dwFlags 
= 0 ; // SHCMBF_EMPTYBAR; 
 267     mbi
.hInstRes 
= wxGetInstance(); 
 269     if (!SHCreateMenuBar(&mbi
)) 
 271         wxFAIL_MSG( _T("SHCreateMenuBar failed") ); 
 275     SetHWND((WXHWND
) mbi
.hwndMB
); 
 277     HWND hWnd 
= CommandBar_Create(wxGetInstance(), (HWND
) GetParent()->GetHWND(), GetId()); 
 278     SetHWND((WXHWND
) hWnd
); 
 281     // install wxWidgets window proc for this window 
 290 void wxToolBar::Recreate() 
 293     const HWND hwndOld 
= GetHwnd(); 
 296         // we haven't been created yet, no need to recreate 
 300     // get the position and size before unsubclassing the old toolbar 
 301     const wxPoint pos 
= GetPosition(); 
 302     const wxSize size 
= GetSize(); 
 306     if ( !MSWCreateToolbar(pos
, size
) ) 
 309         wxFAIL_MSG( _T("recreating the toolbar failed") ); 
 314     // reparent all our children under the new toolbar 
 315     for ( wxWindowList::compatibility_iterator node 
= m_children
.GetFirst(); 
 317           node 
= node
->GetNext() ) 
 319         wxWindow 
*win 
= node
->GetData(); 
 320         if ( !win
->IsTopLevel() ) 
 321             ::SetParent(GetHwndOf(win
), GetHwnd()); 
 324     // only destroy the old toolbar now -- after all the children had been 
 326     ::DestroyWindow(hwndOld
); 
 328     // it is for the old bitmap control and can't be used with the new one 
 331         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 340 wxToolBar::~wxToolBar() 
 343         GetMenuBar()->SetToolBar(NULL
); 
 345     // we must refresh the frame size when the toolbar is deleted but the frame 
 346     // is not - otherwise toolbar leaves a hole in the place it used to occupy 
 347     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
 348     if ( frame 
&& !frame
->IsBeingDeleted() ) 
 350         frame
->SendSizeEvent(); 
 355         ::DeleteObject((HBITMAP
) m_hBitmap
); 
 359 wxSize 
wxToolBar::DoGetBestSize() const 
 361     wxSize sizeBest 
= GetToolSize(); 
 362     sizeBest
.x 
*= GetToolsCount(); 
 364     // reverse horz and vertical components if necessary 
 365     return HasFlag(wxTB_VERTICAL
) ? wxSize(sizeBest
.y
, sizeBest
.x
) : sizeBest
; 
 368 // Return HMENU for the menu associated with the commandbar 
 369 WXHMENU 
wxToolBar::GetHMenu() 
 371 #if defined(__HANDHELDPC__) 
 377         return (WXHMENU
) (HMENU
)::SendMessage((HWND
) GetHWND(), SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0); 
 385 WXDWORD 
wxToolBar::MSWGetStyle(long style
, WXDWORD 
*exstyle
) const 
 387     // toolbars never have border, giving one to them results in broken 
 389     WXDWORD msStyle 
= wxControl::MSWGetStyle
 
 391                         (style 
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
 
 394     // always include this one, it never hurts and setting it later only if we 
 395     // do have tooltips wouldn't work 
 396     msStyle 
|= TBSTYLE_TOOLTIPS
; 
 398     if ( style 
& (wxTB_FLAT 
| wxTB_HORZ_LAYOUT
) ) 
 400         // static as it doesn't change during the program lifetime 
 401         static int s_verComCtl 
= wxTheApp
->GetComCtl32Version(); 
 403         // comctl32.dll 4.00 doesn't support the flat toolbars and using this 
 404         // style with 6.00 (part of Windows XP) leads to the toolbar with 
 405         // incorrect background colour - and not using it still results in the 
 406         // correct (flat) toolbar, so don't use it there 
 407         if ( s_verComCtl 
> 400 && s_verComCtl 
< 600 ) 
 409             msStyle 
|= TBSTYLE_FLAT 
| TBSTYLE_TRANSPARENT
; 
 412         if ( s_verComCtl 
>= 470 && style 
& wxTB_HORZ_LAYOUT 
) 
 414             msStyle 
|= TBSTYLE_LIST
; 
 418     if ( style 
& wxTB_NODIVIDER 
) 
 419         msStyle 
|= CCS_NODIVIDER
; 
 421     if ( style 
& wxTB_NOALIGN 
) 
 422         msStyle 
|= CCS_NOPARENTALIGN
; 
 424     if ( style 
& wxTB_VERTICAL 
) 
 430 // ---------------------------------------------------------------------------- 
 431 // adding/removing tools 
 432 // ---------------------------------------------------------------------------- 
 434 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 436     // nothing special to do here - we really create the toolbar buttons in 
 443 bool wxToolBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 445     // the main difficulty we have here is with the controls in the toolbars: 
 446     // as we (sometimes) use several separators to cover up the space used by 
 447     // them, the indices are not the same for us and the toolbar 
 449     // first determine the position of the first button to delete: it may be 
 450     // different from pos if we use several separators to cover the space used 
 452     wxToolBarToolsList::compatibility_iterator node
; 
 453     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 455         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 458             // let node point to the next node in the list 
 459             node 
= node
->GetNext(); 
 464         if ( tool2
->IsControl() ) 
 466             pos 
+= ((wxToolBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 470     // now determine the number of buttons to delete and the area taken by them 
 471     size_t nButtonsToDelete 
= 1; 
 473     // get the size of the button we're going to delete 
 475     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 477         wxLogLastError(_T("TB_GETITEMRECT")); 
 480     int width 
= r
.right 
- r
.left
; 
 482     if ( tool
->IsControl() ) 
 484         nButtonsToDelete 
= ((wxToolBarTool 
*)tool
)->GetSeparatorsCount(); 
 486         width 
*= nButtonsToDelete
; 
 489     // do delete all buttons 
 490     m_nButtons 
-= nButtonsToDelete
; 
 491     while ( nButtonsToDelete
-- > 0 ) 
 493         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 495             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 503     // and finally reposition all the controls after this button (the toolbar 
 504     // takes care of all normal items) 
 505     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 507         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 508         if ( tool2
->IsControl() ) 
 511             wxControl 
*control 
= tool2
->GetControl(); 
 512             control
->GetPosition(&x
, NULL
); 
 513             control
->Move(x 
- width
, wxDefaultCoord
); 
 520 struct wxToolBarIdMapping
 
 526 static wxToolBarIdMapping sm_ToolBarIdMappingArray
[] = 
 528     { wxID_COPY
, STD_COPY 
}, 
 529     { wxID_CUT
, STD_CUT 
}, 
 530     { wxID_FIND
, STD_FIND 
}, 
 531     { wxID_PASTE
, STD_PASTE 
}, 
 532     { wxID_NEW
, STD_FILENEW 
}, 
 533     { wxID_OPEN
, STD_FILEOPEN 
}, 
 534     { wxID_SAVE
, STD_FILESAVE 
}, 
 535     { wxID_PRINT
, STD_PRINT 
}, 
 536     { wxID_PREVIEW
, STD_PRINTPRE 
}, 
 537     { wxID_UNDO
, STD_UNDO  
}, 
 538     { wxID_REDO
, STD_REDOW 
}, 
 539     { wxID_HELP
, STD_HELP 
}, 
 540     { wxID_DELETE
, STD_DELETE 
}, 
 541     { wxID_REPLACE
, STD_REPLACE 
}, 
 542     { wxID_PROPERTIES
, STD_PROPERTIES 
}, 
 543     { wxID_VIEW_DETAILS
, VIEW_DETAILS 
}, 
 544     { wxID_VIEW_SORTDATE
, VIEW_SORTDATE 
}, 
 545     { wxID_VIEW_LARGEICONS
, VIEW_LARGEICONS 
}, 
 546     { wxID_VIEW_SORTNAME
, VIEW_SORTNAME 
}, 
 547     { wxID_VIEW_LIST
, VIEW_LIST 
}, 
 548     { wxID_VIEW_SORTSIZE
, VIEW_SORTSIZE 
}, 
 549     { wxID_VIEW_SMALLICONS
, VIEW_SMALLICONS 
}, 
 550     { wxID_VIEW_SORTTYPE
, VIEW_SORTTYPE 
}, 
 554 static int wxFindIdForwxWinId(int id
) 
 559         if (sm_ToolBarIdMappingArray
[i
].m_wxwinId 
== 0) 
 561         else if (sm_ToolBarIdMappingArray
[i
].m_wxwinId 
== id
) 
 562             return sm_ToolBarIdMappingArray
[i
].m_winceId
; 
 569 bool wxToolBar::Realize() 
 571     const size_t nTools 
= GetToolsCount(); 
 579     // delete all old buttons, if any 
 580     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 582         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 584             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 589     // add the buttons and separators 
 590     // ------------------------------ 
 592     // Use standard buttons 
 593     CommandBar_AddBitmap((HWND
) GetHWND(), HINST_COMMCTRL
, 
 594         IDB_STD_SMALL_COLOR
, 0, 16, 16); 
 596     TBBUTTON 
*buttons 
= new TBBUTTON
[nTools
]; 
 598     // this array will hold the indices of all controls in the toolbar 
 599     wxArrayInt controlIds
; 
 601     bool lastWasRadio 
= false; 
 603     wxToolBarToolsList::Node
* node
; 
 604     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 606         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 608         bool processedThis 
= true; 
 610         TBBUTTON
& button 
= buttons
[i
]; 
 612         wxZeroMemory(button
); 
 614         bool isRadio 
= false; 
 615         switch ( tool
->GetStyle() ) 
 617             case wxTOOL_STYLE_CONTROL
: 
 618                 button
.idCommand 
= tool
->GetId(); 
 619                 // fall through: create just a separator too 
 621             case wxTOOL_STYLE_SEPARATOR
: 
 622                 button
.fsState 
= TBSTATE_ENABLED
; 
 623                 button
.fsStyle 
= TBSTYLE_SEP
; 
 626             case wxTOOL_STYLE_BUTTON
: 
 627 //                if ( !HasFlag(wxTB_NOICONS) ) 
 628 //                    button.iBitmap = bitmapId; 
 630                 if ( HasFlag(wxTB_TEXT
) ) 
 632                     const wxString
& label 
= tool
->GetLabel(); 
 633                     if ( !label
.empty() ) 
 635                         button
.iString 
= (int)label
.c_str(); 
 639                 int winceId 
= wxFindIdForwxWinId(tool
->GetId()); 
 642                     button
.idCommand 
= tool
->GetId(); 
 643 //                if ( !HasFlag(wxTB_NOICONS) ) 
 644                     button
.iBitmap 
= winceId
; 
 647                     processedThis 
= false; 
 649                 if ( tool
->IsEnabled() ) 
 650                     button
.fsState 
|= TBSTATE_ENABLED
; 
 651                 if ( tool
->IsToggled() ) 
 652                     button
.fsState 
|= TBSTATE_CHECKED
; 
 654                 switch ( tool
->GetKind() ) 
 657                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 661                             // the first item in the radio group is checked by 
 662                             // default to be consistent with wxGTK and the menu 
 664                             button
.fsState 
|= TBSTATE_CHECKED
; 
 673                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 677                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 681                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 688         lastWasRadio 
= isRadio
; 
 694     // Add buttons to Commandbar 
 695     if (!CommandBar_AddButtons(GetHwnd(), i
, buttons
)) 
 697         wxLogLastError(wxT("CommandBar_AddButtons")); 
 704     const bool isVertical 
= HasFlag(wxTB_VERTICAL
); 
 706     // Deal with the controls finally 
 707     // ------------------------------ 
 709     // adjust the controls size to fit nicely in the toolbar 
 712     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext(), index
++ ) 
 714         wxToolBarToolBase 
*tool 
= node
->GetData(); 
 716         // we calculate the running y coord for vertical toolbars so we need to 
 717         // get the items size for all items but for the horizontal ones we 
 718         // don't need to deal with the non controls 
 719         bool isControl 
= tool
->IsControl(); 
 720         if ( !isControl 
&& !isVertical 
) 
 723         // note that we use TB_GETITEMRECT and not TB_GETRECT because the 
 724         // latter only appeared in v4.70 of comctl32.dll 
 726         if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, 
 727                             index
, (LPARAM
)(LPRECT
)&r
) ) 
 729             wxLogLastError(wxT("TB_GETITEMRECT")); 
 734             // can only be control if isVertical 
 735             y 
+= r
.bottom 
- r
.top
; 
 740         wxControl 
*control 
= tool
->GetControl(); 
 742         wxSize size 
= control
->GetSize(); 
 744         // the position of the leftmost controls corner 
 747         // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+ 
 748 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) 
 749         // available in headers, now check whether it is available now 
 751         if ( wxTheApp
->GetComCtl32Version() >= 471 ) 
 753             // set the (underlying) separators width to be that of the 
 756             tbbi
.cbSize 
= sizeof(tbbi
); 
 757             tbbi
.dwMask 
= TBIF_SIZE
; 
 759             if ( !::SendMessage(GetHwnd(), TB_SETBUTTONINFO
, 
 760                                 tool
->GetId(), (LPARAM
)&tbbi
) ) 
 762                 // the id is probably invalid? 
 763                 wxLogLastError(wxT("TB_SETBUTTONINFO")); 
 767 #endif // comctl32.dll 4.71 
 768         // TB_SETBUTTONINFO unavailable 
 770             // try adding several separators to fit the controls width 
 771             int widthSep 
= r
.right 
- r
.left
; 
 777             tbb
.fsState 
= TBSTATE_ENABLED
; 
 778             tbb
.fsStyle 
= TBSTYLE_SEP
; 
 780             size_t nSeparators 
= size
.x 
/ widthSep
; 
 781             for ( size_t nSep 
= 0; nSep 
< nSeparators
; nSep
++ ) 
 783                 if ( !::SendMessage(GetHwnd(), TB_INSERTBUTTON
, 
 784                                     index
, (LPARAM
)&tbb
) ) 
 786                     wxLogLastError(wxT("TB_INSERTBUTTON")); 
 792             // remember the number of separators we used - we'd have to 
 793             // delete all of them later 
 794             ((wxToolBarTool 
*)tool
)->SetSeparatorsCount(nSeparators
); 
 796             // adjust the controls width to exactly cover the separators 
 797             control
->SetSize((nSeparators 
+ 1)*widthSep
, wxDefaultCoord
); 
 800         // position the control itself correctly vertically 
 801         int height 
= r
.bottom 
- r
.top
; 
 802         int diff 
= height 
- size
.y
; 
 805             // the control is too high, resize to fit 
 806             control
->SetSize(wxDefaultCoord
, height 
- 2); 
 817             y 
+= height 
+ 2*GetMargins().y
; 
 819         else // horizontal toolbar 
 827         control
->Move(left
, top 
+ (diff 
+ 1) / 2); 
 830     // the max index is the "real" number of buttons - i.e. counting even the 
 831     // separators which we added just for aligning the controls 
 836         if ( m_maxRows 
== 0 ) 
 838             // if not set yet, only one row 
 842     else if ( m_nButtons 
> 0 ) // vertical non empty toolbar 
 844         if ( m_maxRows 
== 0 ) 
 846             // if not set yet, have one column 
 855 // ---------------------------------------------------------------------------- 
 857 // ---------------------------------------------------------------------------- 
 859 bool wxToolBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id
) 
 861     wxToolBarToolBase 
*tool 
= FindById((int)id
); 
 864         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
); 
 865         event
.SetEventObject(this); 
 869         return GetEventHandler()->ProcessEvent(event
); 
 872     if ( tool
->CanBeToggled() ) 
 874         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
 875         tool
->Toggle((state 
& TBSTATE_CHECKED
) != 0); 
 878     bool toggled 
= tool
->IsToggled(); 
 880     // avoid sending the event when a radio button is released, this is not 
 882     if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO 
|| toggled 
) 
 884         // OnLeftClick() can veto the button state change - for buttons which 
 885         // may be toggled only, of couse 
 886         if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
 890             tool
->SetToggle(toggled
); 
 892             ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0)); 
 899 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl
), 
 901                             WXLPARAM 
*WXUNUSED(result
)) 
 904     // First check if this applies to us 
 905     NMHDR 
*hdr 
= (NMHDR 
*)lParam
; 
 907     // the tooltips control created by the toolbar is sometimes Unicode, even 
 908     // in an ANSI application - this seems to be a bug in comctl32.dll v5 
 909     UINT code 
= hdr
->code
; 
 910     if ( (code 
!= (UINT
) TTN_NEEDTEXTA
) && (code 
!= (UINT
) TTN_NEEDTEXTW
) ) 
 913     HWND toolTipWnd 
= (HWND
)::SendMessage((HWND
)GetHWND(), TB_GETTOOLTIPS
, 0, 0); 
 914     if ( toolTipWnd 
!= hdr
->hwndFrom 
) 
 917     LPTOOLTIPTEXT ttText 
= (LPTOOLTIPTEXT
)lParam
; 
 918     int id 
= (int)ttText
->hdr
.idFrom
; 
 920     wxToolBarToolBase 
*tool 
= FindById(id
); 
 924     return HandleTooltipNotify(code
, lParam
, tool
->GetShortHelp()); 
 931 // ---------------------------------------------------------------------------- 
 933 // ---------------------------------------------------------------------------- 
 935 void wxToolBar::SetToolBitmapSize(const wxSize
& size
) 
 937     wxToolBarBase::SetToolBitmapSize(size
); 
 939     ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE
, 0, MAKELONG(size
.x
, size
.y
)); 
 942 void wxToolBar::SetRows(int nRows
) 
 944     if ( nRows 
== m_maxRows 
) 
 946         // avoid resizing the frame uselessly 
 950     // TRUE in wParam means to create at least as many rows, FALSE - 
 953     ::SendMessage(GetHwnd(), TB_SETROWS
, 
 954                   MAKEWPARAM(nRows
, !(GetWindowStyle() & wxTB_VERTICAL
)), 
 962 // The button size is bigger than the bitmap size 
 963 wxSize 
wxToolBar::GetToolSize() const 
 965     // TB_GETBUTTONSIZE is supported from version 4.70 
 966 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \ 
 967     && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) 
 968     if ( wxTheApp
->GetComCtl32Version() >= 470 ) 
 970         DWORD dw 
= ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE
, 0, 0); 
 972         return wxSize(LOWORD(dw
), HIWORD(dw
)); 
 975 #endif // comctl32.dll 4.70+ 
 978         return wxSize(m_defaultWidth 
+ 8, m_defaultHeight 
+ 7); 
 983 wxToolBarToolBase 
*GetItemSkippingDummySpacers(const wxToolBarToolsList
& tools
, 
 986     wxToolBarToolsList::compatibility_iterator current 
= tools
.GetFirst(); 
 988     for ( ; current 
!= 0; current 
= current
->GetNext() ) 
 991             return current
->GetData(); 
 993         wxToolBarTool 
*tool 
= (wxToolBarTool 
*)current
->GetData(); 
 994         size_t separators 
= tool
->GetSeparatorsCount(); 
 996         // if it is a normal button, sepcount == 0, so skip 1 item (the button) 
 997         // otherwise, skip as many items as the separator count, plus the 
 999         index 
-= separators 
? separators 
+ 1 : 1; 
1005 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord x
, wxCoord y
) const 
1010     int index 
= (int)::SendMessage(GetHwnd(), TB_HITTEST
, 0, (LPARAM
)&pt
); 
1011     // MBN: when the point ( x, y ) is close to the toolbar border 
1012     //      TB_HITTEST returns m_nButtons ( not -1 ) 
1013     if ( index 
< 0 || (size_t)index 
>= m_nButtons 
) 
1015         // it's a separator or there is no tool at all there 
1016         return (wxToolBarToolBase 
*)NULL
; 
1019     // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers 
1020 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 ) 
1021     if ( wxTheApp
->GetComCtl32Version() >= 471 ) 
1023         return m_tools
.Item((size_t)index
)->GetData(); 
1028         return GetItemSkippingDummySpacers( m_tools
, (size_t) index 
); 
1032 void wxToolBar::UpdateSize() 
1034     // the toolbar size changed 
1035     ::SendMessage(GetHwnd(), TB_AUTOSIZE
, 0, 0); 
1037     // we must also refresh the frame after the toolbar size (possibly) changed 
1038     wxFrame 
*frame 
= wxDynamicCast(GetParent(), wxFrame
); 
1041         frame
->SendSizeEvent(); 
1045 // ---------------------------------------------------------------------------- 
1047 // --------------------------------------------------------------------------- 
1049 void wxToolBar::SetWindowStyleFlag(long style
) 
1051     // the style bits whose changes force us to recreate the toolbar 
1052     static const long MASK_NEEDS_RECREATE 
= wxTB_TEXT 
| wxTB_NOICONS
; 
1054     const long styleOld 
= GetWindowStyle(); 
1056     wxToolBarBase::SetWindowStyleFlag(style
); 
1058     // don't recreate an empty toolbar: not only this is unnecessary, but it is 
1059     // also fatal as we'd then try to recreate the toolbar when it's just being 
1061     if ( GetToolsCount() && 
1062             (style 
& MASK_NEEDS_RECREATE
) != (styleOld 
& MASK_NEEDS_RECREATE
) ) 
1064         // to remove the text labels, simply re-realizing the toolbar is enough 
1065         // but I don't know of any way to add the text to an existing toolbar 
1066         // other than by recreating it entirely 
1071 // ---------------------------------------------------------------------------- 
1073 // ---------------------------------------------------------------------------- 
1075 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*tool
, bool enable
) 
1077     ::SendMessage(GetHwnd(), TB_ENABLEBUTTON
, 
1078                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(enable
, 0)); 
1081 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*tool
, bool toggle
) 
1083     ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, 
1084                   (WPARAM
)tool
->GetId(), (LPARAM
)MAKELONG(toggle
, 0)); 
1087 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
1089     // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or 
1090     //     without, so we really need to delete the button and recreate it here 
1091     wxFAIL_MSG( _T("not implemented") ); 
1094 // ---------------------------------------------------------------------------- 
1096 // ---------------------------------------------------------------------------- 
1098 // Responds to colour changes, and passes event on to children. 
1099 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent
& event
) 
1101     wxRGBToColour(m_backgroundColour
, ::GetSysColor(COLOR_BTNFACE
)); 
1103     // Remap the buttons 
1106     // Relayout the toolbar 
1107     int nrows 
= m_maxRows
; 
1108     m_maxRows 
= 0;      // otherwise SetRows() wouldn't do anything 
1113     // let the event propagate further 
1117 void wxToolBar::OnMouseEvent(wxMouseEvent
& event
) 
1119     if (event
.Leaving() && m_pInTool
) 
1126     if (event
.RightDown()) 
1128         // For now, we don't have an id. Later we could 
1129         // try finding the tool. 
1130         OnRightClick((int)-1, event
.GetX(), event
.GetY()); 
1138 void wxToolBar::HandleMouseMove(WXWPARAM 
WXUNUSED(wParam
), WXLPARAM lParam
) 
1140     wxCoord x 
= GET_X_LPARAM(lParam
), 
1141             y 
= GET_Y_LPARAM(lParam
); 
1142     wxToolBarToolBase
* tool 
= FindToolForPosition( x
, y 
); 
1144     // cursor left current tool 
1145     if( tool 
!= m_pInTool 
&& !tool 
) 
1151     // cursor entered a tool 
1152     if( tool 
!= m_pInTool 
&& tool 
) 
1155         OnMouseEnter( tool
->GetId() ); 
1159 WXLRESULT 
wxToolBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
1165             if ( HandleSize(wParam
, lParam
) ) 
1170             // we don't handle mouse moves, so always pass the message to 
1171             // wxControl::MSWWindowProc 
1172             HandleMouseMove(wParam
, lParam
); 
1176     return wxControl::MSWWindowProc(nMsg
, wParam
, lParam
); 
1179 #endif // wxUSE_TOOLBAR && Win95