1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  27 // Use the WinCE-specific toolbar only if we're either compiling 
  28 // with a WinCE earlier than 4, or we wish to emulate a PocketPC-style UI 
  29 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (_WIN32_WCE < 400 || defined(__POCKETPC__) || defined(__SMARTPHONE__)) 
  32     #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 #include "wx/toolbar.h" 
  44 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__) 
  48 // include <commctrl.h> "properly" 
  49 #include "wx/msw/wrapcctl.h" 
  51 #include "wx/msw/private.h" 
  57 #if defined(WINCE_WITHOUT_COMMANDBAR) 
  60 #include "wx/msw/wince/missing.h" 
  62 #include "wx/msw/winundef.h" 
  64 #if !defined(__SMARTPHONE__) 
  66 ///////////// This implementation is for PocketPC. 
  67 ///////////// See later for the Smartphone dummy toolbar class. 
  69 // ---------------------------------------------------------------------------- 
  71 // ---------------------------------------------------------------------------- 
  73 IMPLEMENT_DYNAMIC_CLASS(wxToolMenuBar
, wxToolBar
) 
  75 BEGIN_EVENT_TABLE(wxToolMenuBar
, wxToolBar
) 
  78 // ---------------------------------------------------------------------------- 
  80 // ---------------------------------------------------------------------------- 
  82 class wxToolMenuBarTool 
: public wxToolBarToolBase
 
  85     wxToolMenuBarTool(wxToolBar 
*tbar
, 
  87                   const wxString
& label
, 
  88                   const wxBitmap
& bmpNormal
, 
  89                   const wxBitmap
& bmpDisabled
, 
  92                   const wxString
& shortHelp
, 
  93                   const wxString
& longHelp
) 
  94         : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
  95                             clientData
, shortHelp
, longHelp
) 
 101     wxToolMenuBarTool(wxToolBar 
*tbar
, wxControl 
*control
) 
 102         : wxToolBarToolBase(tbar
, control
) 
 108     virtual void SetLabel(const wxString
& label
) 
 110         if ( label 
== m_label 
) 
 113         wxToolBarToolBase::SetLabel(label
); 
 115         // we need to update the label shown in the toolbar because it has a 
 116         // pointer to the internal buffer of the old label 
 118         // TODO: use TB_SETBUTTONINFO 
 121     // set/get the number of separators which we use to cover the space used by 
 122     // a control in the toolbar 
 123     void SetSeparatorsCount(size_t count
) { m_nSepCount 
= count
; } 
 124     size_t GetSeparatorsCount() const { return m_nSepCount
; } 
 126     void SetBitmapIndex(int idx
) { m_bitmapIndex 
= idx
; } 
 127     int GetBitmapIndex() const { return m_bitmapIndex
; } 
 135 // ============================================================================ 
 137 // ============================================================================ 
 139 // ---------------------------------------------------------------------------- 
 141 // ---------------------------------------------------------------------------- 
 143 wxToolBarToolBase 
*wxToolMenuBar::CreateTool(int id
, 
 144                                          const wxString
& label
, 
 145                                          const wxBitmap
& bmpNormal
, 
 146                                          const wxBitmap
& bmpDisabled
, 
 148                                          wxObject 
*clientData
, 
 149                                          const wxString
& shortHelp
, 
 150                                          const wxString
& longHelp
) 
 152     return new wxToolMenuBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 153                              clientData
, shortHelp
, longHelp
); 
 156 wxToolBarToolBase 
*wxToolMenuBar::CreateTool(wxControl 
*control
) 
 158     return new wxToolMenuBarTool(this, control
); 
 161 // ---------------------------------------------------------------------------- 
 162 // wxToolBar construction 
 163 // ---------------------------------------------------------------------------- 
 165 void wxToolMenuBar::Init() 
 173 bool wxToolMenuBar::Create(wxWindow 
*parent
, 
 178                        const wxString
& name
, 
 181     // common initialisation 
 182     if ( !CreateControl(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) ) 
 185     // MSW-specific initialisation 
 186     if ( !MSWCreateToolbar(pos
, size
, menuBar
) ) 
 189     // set up the colors and fonts 
 190     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR
)); 
 191     SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
)); 
 196 bool wxToolMenuBar::MSWCreateToolbar(const wxPoint
& WXUNUSED(pos
), const wxSize
& WXUNUSED(size
), wxMenuBar
* menuBar
) 
 200         m_menuBar
->SetToolBar(this); 
 202 #if defined(WINCE_WITHOUT_COMMANDBAR) 
 203     // Create the menubar. 
 206     memset (&mbi
, 0, sizeof (SHMENUBARINFO
)); 
 207     mbi
.cbSize     
= sizeof (SHMENUBARINFO
); 
 208     mbi
.hwndParent 
= (HWND
) GetParent()->GetHWND(); 
 209 #ifdef __SMARTPHONE__ 
 210     mbi
.nToolBarId 
= 5002; 
 212     mbi
.nToolBarId 
= 5000; 
 216     mbi
.dwFlags 
= 0 ; // SHCMBF_EMPTYBAR; 
 217     mbi
.hInstRes 
= wxGetInstance(); 
 219     if (!SHCreateMenuBar(&mbi
)) 
 221         wxFAIL_MSG( _T("SHCreateMenuBar failed") ); 
 225     SetHWND((WXHWND
) mbi
.hwndMB
); 
 227     HWND hWnd 
= CommandBar_Create(wxGetInstance(), (HWND
) GetParent()->GetHWND(), GetId()); 
 228     SetHWND((WXHWND
) hWnd
); 
 231     // install wxWidgets window proc for this window 
 240 void wxToolMenuBar::Recreate() 
 245 wxToolMenuBar::~wxToolMenuBar() 
 248         GetMenuBar()->SetToolBar(NULL
); 
 251 // Return HMENU for the menu associated with the commandbar 
 252 WXHMENU 
wxToolMenuBar::GetHMenu() 
 254 #if defined(__HANDHELDPC__) 
 259         return (WXHMENU
) (HMENU
)::SendMessage((HWND
) GetHWND(), SHCMBM_GETMENU
, (WPARAM
)0, (LPARAM
)0); 
 266 // ---------------------------------------------------------------------------- 
 267 // adding/removing tools 
 268 // ---------------------------------------------------------------------------- 
 270 bool wxToolMenuBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 272     // nothing special to do here - we really create the toolbar buttons in 
 279 bool wxToolMenuBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 281     // the main difficulty we have here is with the controls in the toolbars: 
 282     // as we (sometimes) use several separators to cover up the space used by 
 283     // them, the indices are not the same for us and the toolbar 
 285     // first determine the position of the first button to delete: it may be 
 286     // different from pos if we use several separators to cover the space used 
 288     wxToolBarToolsList::compatibility_iterator node
; 
 289     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 291         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 294             // let node point to the next node in the list 
 295             node 
= node
->GetNext(); 
 300         if ( tool2
->IsControl() ) 
 302             pos 
+= ((wxToolMenuBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 306     // now determine the number of buttons to delete and the area taken by them 
 307     size_t nButtonsToDelete 
= 1; 
 309     // get the size of the button we're going to delete 
 311     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 313         wxLogLastError(_T("TB_GETITEMRECT")); 
 316     int width 
= r
.right 
- r
.left
; 
 318     if ( tool
->IsControl() ) 
 320         nButtonsToDelete 
= ((wxToolMenuBarTool 
*)tool
)->GetSeparatorsCount(); 
 322         width 
*= nButtonsToDelete
; 
 325     // do delete all buttons 
 326     m_nButtons 
-= nButtonsToDelete
; 
 327     while ( nButtonsToDelete
-- > 0 ) 
 329         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 331             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 339     // and finally reposition all the controls after this button (the toolbar 
 340     // takes care of all normal items) 
 341     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 343         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 344         if ( tool2
->IsControl() ) 
 347             wxControl 
*control 
= tool2
->GetControl(); 
 348             control
->GetPosition(&x
, NULL
); 
 349             control
->Move(x 
- width
, wxDefaultCoord
); 
 356 bool wxToolMenuBar::Realize() 
 358     const size_t nTools 
= GetToolsCount(); 
 366     // delete all old buttons, if any 
 367     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 369         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 371             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 376     bool lastWasRadio 
= false; 
 377     wxToolBarToolsList::Node
* node
; 
 378     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 380         wxToolMenuBarTool 
*tool 
= (wxToolMenuBarTool
*) node
->GetData(); 
 382         TBBUTTON buttons
[1] ; 
 384         TBBUTTON
& button 
= buttons
[0]; 
 386         wxZeroMemory(button
); 
 388         bool isRadio 
= false; 
 389         switch ( tool
->GetStyle() ) 
 391             case wxTOOL_STYLE_CONTROL
: 
 392                 button
.idCommand 
= tool
->GetId(); 
 393                 // fall through: create just a separator too 
 394                 // TODO: controls are not yet supported on wxToolMenuBar. 
 396             case wxTOOL_STYLE_SEPARATOR
: 
 397                 button
.fsState 
= TBSTATE_ENABLED
; 
 398                 button
.fsStyle 
= TBSTYLE_SEP
; 
 401             case wxTOOL_STYLE_BUTTON
: 
 403                 if ( HasFlag(wxTB_TEXT
) ) 
 405                     const wxString
& label 
= tool
->GetLabel(); 
 406                     if ( !label
.empty() ) 
 408                         button
.iString 
= (int)label
.c_str(); 
 412                 const wxBitmap
& bmp 
= tool
->GetNormalBitmap(); 
 414                 wxBitmap bmpToUse 
= bmp
; 
 416                 if (bmp
.GetWidth() < 16 || bmp
.GetHeight() < 16 || bmp
.GetMask() != NULL
) 
 420                     memDC
.SelectObject(b
); 
 421                     wxColour col 
= wxColour(192,192,192); 
 422                     memDC
.SetBackground(wxBrush(col
)); 
 424                     int x 
= (16 - bmp
.GetWidth())/2; 
 425                     int y 
= (16 - bmp
.GetHeight())/2; 
 426                     memDC
.DrawBitmap(bmp
, x
, y
, true); 
 427                     memDC
.SelectObject(wxNullBitmap
); 
 430                     tool
->SetNormalBitmap(b
); 
 436                     n 
= ::CommandBar_AddBitmap( (HWND
) GetHWND(), NULL
, (int) (HBITMAP
) bmpToUse
.GetHBITMAP(), 
 440                 button
.idCommand 
= tool
->GetId(); 
 443                 if ( tool
->IsEnabled() ) 
 444                     button
.fsState 
|= TBSTATE_ENABLED
; 
 445                 if ( tool
->IsToggled() ) 
 446                     button
.fsState 
|= TBSTATE_CHECKED
; 
 448                 switch ( tool
->GetKind() ) 
 451                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 455                             // the first item in the radio group is checked by 
 456                             // default to be consistent with wxGTK and the menu 
 458                             button
.fsState 
|= TBSTATE_CHECKED
; 
 467                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 471                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 475                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 480         if ( !::CommandBar_AddButtons( (HWND
) GetHWND(), 1, buttons 
) ) 
 482             wxFAIL_MSG( wxT("Could not add toolbar button.")); 
 485         lastWasRadio 
= isRadio
; 
 491 bool wxToolMenuBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id
) 
 493     wxToolBarToolBase 
*tool 
= FindById((int)id
); 
 498             wxMenuItem 
*item 
= m_menuBar
->FindItem(id
); 
 499             if (item 
&& item
->IsCheckable()) 
 505         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
); 
 506         event
.SetEventObject(this); 
 510         return GetEventHandler()->ProcessEvent(event
); 
 513     if ( tool
->CanBeToggled() ) 
 515         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
 516         tool
->Toggle((state 
& TBSTATE_CHECKED
) != 0); 
 519     bool toggled 
= tool
->IsToggled(); 
 521     // avoid sending the event when a radio button is released, this is not 
 523     if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO 
|| toggled 
) 
 525         // OnLeftClick() can veto the button state change - for buttons which 
 526         // may be toggled only, of couse 
 527         if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
 531             tool
->SetToggle(toggled
); 
 533             ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0)); 
 540 WXLRESULT 
wxToolMenuBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 548             // we don't handle mouse moves, so always pass the message to 
 549             // wxControl::MSWWindowProc 
 550             HandleMouseMove(wParam
, lParam
); 
 557     return MSWDefWindowProc(nMsg
, wParam
, lParam
); 
 563 ////////////// For Smartphone 
 565 // ---------------------------------------------------------------------------- 
 567 // ---------------------------------------------------------------------------- 
 569 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
) 
 571 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 574 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 575                                          const wxString
& label
, 
 576                                          const wxBitmap
& bmpNormal
, 
 577                                          const wxBitmap
& bmpDisabled
, 
 579                                          wxObject 
*clientData
, 
 580                                          const wxString
& shortHelp
, 
 581                                          const wxString
& longHelp
) 
 583     return new wxToolBarToolBase(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 584                              clientData
, shortHelp
, longHelp
); 
 587 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 589     return new wxToolBarToolBase(this, control
); 
 592 bool wxToolBar::Create(wxWindow 
*parent
, 
 593                        wxWindowID 
WXUNUSED(id
), 
 594                        const wxPoint
& WXUNUSED(pos
), 
 595                        const wxSize
& WXUNUSED(size
), 
 597                        const wxString
& name
) 
 599     // TODO: we may need to make this a dummy hidden window to 
 600     // satisfy other parts of wxWidgets. 
 602     parent
->AddChild(this); 
 604     SetWindowStyle(style
); 
 610 // ---------------------------------------------------------------------------- 
 611 // adding/removing tools 
 612 // ---------------------------------------------------------------------------- 
 614 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 620 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 626 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) const 
 631 // ---------------------------------------------------------------------------- 
 633 // ---------------------------------------------------------------------------- 
 635 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(enable
)) 
 639 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 643 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 645     wxFAIL_MSG( _T("not implemented") ); 
 651 #endif // wxUSE_TOOLBAR