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__)) 
  31 #include "wx/toolbar.h" 
  34     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly" 
  35     #include "wx/dynarray.h" 
  39     #include "wx/settings.h" 
  40     #include "wx/bitmap.h" 
  41     #include "wx/dcmemory.h" 
  42     #include "wx/control.h" 
  45 #if !defined(__GNUWIN32__) 
  49 #include "wx/msw/private.h" 
  55 #if defined(WINCE_WITHOUT_COMMANDBAR) 
  57   #include "wx/msw/wince/resources.h" 
  59 #include "wx/msw/wince/missing.h" 
  61 #include "wx/msw/winundef.h" 
  63 #if !defined(__SMARTPHONE__) 
  65 ///////////// This implementation is for PocketPC. 
  66 ///////////// See later for the Smartphone dummy toolbar class. 
  68 // ---------------------------------------------------------------------------- 
  70 // ---------------------------------------------------------------------------- 
  72 IMPLEMENT_DYNAMIC_CLASS(wxToolMenuBar
, wxToolBar
) 
  74 BEGIN_EVENT_TABLE(wxToolMenuBar
, wxToolBar
) 
  77 // ---------------------------------------------------------------------------- 
  79 // ---------------------------------------------------------------------------- 
  81 class wxToolMenuBarTool 
: public wxToolBarToolBase
 
  84     wxToolMenuBarTool(wxToolBar 
*tbar
, 
  86                   const wxString
& label
, 
  87                   const wxBitmap
& bmpNormal
, 
  88                   const wxBitmap
& bmpDisabled
, 
  91                   const wxString
& shortHelp
, 
  92                   const wxString
& longHelp
) 
  93         : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
  94                             clientData
, shortHelp
, longHelp
) 
 100     wxToolMenuBarTool(wxToolBar 
*tbar
, wxControl 
*control
, const wxString
& label
) 
 101         : wxToolBarToolBase(tbar
, control
, label
) 
 107     virtual void SetLabel(const wxString
& label
) 
 109         if ( label 
== m_label 
) 
 112         wxToolBarToolBase::SetLabel(label
); 
 114         // we need to update the label shown in the toolbar because it has a 
 115         // pointer to the internal buffer of the old label 
 117         // TODO: use TB_SETBUTTONINFO 
 120     // set/get the number of separators which we use to cover the space used by 
 121     // a control in the toolbar 
 122     void SetSeparatorsCount(size_t count
) { m_nSepCount 
= count
; } 
 123     size_t GetSeparatorsCount() const { return m_nSepCount
; } 
 125     void SetBitmapIndex(int idx
) { m_bitmapIndex 
= idx
; } 
 126     int GetBitmapIndex() const { return m_bitmapIndex
; } 
 134 // ============================================================================ 
 136 // ============================================================================ 
 138 // ---------------------------------------------------------------------------- 
 140 // ---------------------------------------------------------------------------- 
 142 wxToolBarToolBase 
*wxToolMenuBar::CreateTool(int id
, 
 143                                          const wxString
& label
, 
 144                                          const wxBitmap
& bmpNormal
, 
 145                                          const wxBitmap
& bmpDisabled
, 
 147                                          wxObject 
*clientData
, 
 148                                          const wxString
& shortHelp
, 
 149                                          const wxString
& longHelp
) 
 151     return new wxToolMenuBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 152                              clientData
, shortHelp
, longHelp
); 
 156 wxToolMenuBar::CreateTool(wxControl 
*control
, const wxString
& label
) 
 158     return new wxToolMenuBarTool(this, control
, label
); 
 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
), 
 197                                      const wxSize
& WXUNUSED(size
), 
 202         m_menuBar
->SetToolBar(this); 
 204     HWND hwndParent 
= GetHwndOf(GetParent()); 
 205     wxCHECK_MSG( hwndParent
, false, _T("should have valid parent HWND") ); 
 207 #if defined(WINCE_WITHOUT_COMMANDBAR) 
 208     // create the menubar. 
 209     WinStruct
<SHMENUBARINFO
> mbi
; 
 211     mbi
.hwndParent 
= hwndParent
; 
 212     mbi
.nToolBarId 
= wxIDM_SHMENU
; 
 213     mbi
.hInstRes 
= wxGetInstance(); 
 215     if ( !SHCreateMenuBar(&mbi
) ) 
 217         wxFAIL_MSG( _T("SHCreateMenuBar failed") ); 
 221     SetHWND((WXHWND
) mbi
.hwndMB
); 
 223     HWND hWnd 
= CommandBar_Create(wxGetInstance(), hwndParent
, GetId()); 
 224     SetHWND((WXHWND
) hWnd
); 
 227     // install wxWidgets window proc for this window 
 236 void wxToolMenuBar::Recreate() 
 241 wxToolMenuBar::~wxToolMenuBar() 
 244         GetMenuBar()->SetToolBar(NULL
); 
 247 // Return HMENU for the menu associated with the commandbar 
 248 WXHMENU 
wxToolMenuBar::GetHMenu() 
 250 #if !defined(__HANDHELDPC__) 
 253         return (WXHMENU
)::SendMessage(GetHwnd(), SHCMBM_GETMENU
, 0, 0); 
 260 // ---------------------------------------------------------------------------- 
 261 // adding/removing tools 
 262 // ---------------------------------------------------------------------------- 
 264 bool wxToolMenuBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 266     // nothing special to do here - we really create the toolbar buttons in 
 273 bool wxToolMenuBar::DoDeleteTool(size_t pos
, wxToolBarToolBase 
*tool
) 
 275     // the main difficulty we have here is with the controls in the toolbars: 
 276     // as we (sometimes) use several separators to cover up the space used by 
 277     // them, the indices are not the same for us and the toolbar 
 279     // first determine the position of the first button to delete: it may be 
 280     // different from pos if we use several separators to cover the space used 
 282     wxToolBarToolsList::compatibility_iterator node
; 
 283     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 285         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 288             // let node point to the next node in the list 
 289             node 
= node
->GetNext(); 
 294         if ( tool2
->IsControl() ) 
 296             pos 
+= ((wxToolMenuBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 300     // now determine the number of buttons to delete and the area taken by them 
 301     size_t nButtonsToDelete 
= 1; 
 303     // get the size of the button we're going to delete 
 305     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 307         wxLogLastError(_T("TB_GETITEMRECT")); 
 310     int width 
= r
.right 
- r
.left
; 
 312     if ( tool
->IsControl() ) 
 314         nButtonsToDelete 
= ((wxToolMenuBarTool 
*)tool
)->GetSeparatorsCount(); 
 316         width 
*= nButtonsToDelete
; 
 319     // do delete all buttons 
 320     m_nButtons 
-= nButtonsToDelete
; 
 321     while ( nButtonsToDelete
-- > 0 ) 
 323         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 325             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 333     // and finally reposition all the controls after this button (the toolbar 
 334     // takes care of all normal items) 
 335     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 337         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 338         if ( tool2
->IsControl() ) 
 341             wxControl 
*control 
= tool2
->GetControl(); 
 342             control
->GetPosition(&x
, NULL
); 
 343             control
->Move(x 
- width
, wxDefaultCoord
); 
 350 bool wxToolMenuBar::Realize() 
 352     const size_t nTools 
= GetToolsCount(); 
 360     // delete all old buttons, if any 
 361     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 363         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 365             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 370     bool lastWasRadio 
= false; 
 371     wxToolBarToolsList::Node
* node
; 
 372     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 374         wxToolMenuBarTool 
*tool 
= (wxToolMenuBarTool
*) node
->GetData(); 
 376         TBBUTTON buttons
[1] ; 
 378         TBBUTTON
& button 
= buttons
[0]; 
 380         wxZeroMemory(button
); 
 382         bool isRadio 
= false; 
 383         switch ( tool
->GetStyle() ) 
 385             case wxTOOL_STYLE_CONTROL
: 
 386                 button
.idCommand 
= tool
->GetId(); 
 387                 // fall through: create just a separator too 
 388                 // TODO: controls are not yet supported on wxToolMenuBar. 
 390             case wxTOOL_STYLE_SEPARATOR
: 
 391                 button
.fsState 
= TBSTATE_ENABLED
; 
 392                 button
.fsStyle 
= TBSTYLE_SEP
; 
 395             case wxTOOL_STYLE_BUTTON
: 
 397                 if ( HasFlag(wxTB_TEXT
) ) 
 399                     const wxString
& label 
= tool
->GetLabel(); 
 400                     if ( !label
.empty() ) 
 402                         button
.iString 
= (int)label
.wx_str(); 
 406                 const wxBitmap
& bmp 
= tool
->GetNormalBitmap(); 
 408                 wxBitmap bmpToUse 
= bmp
; 
 410                 if (bmp
.GetWidth() < 16 || bmp
.GetHeight() < 16 || bmp
.GetMask() != NULL
) 
 414                     memDC
.SelectObject(b
); 
 415                     wxColour col 
= wxColour(192,192,192); 
 416                     memDC
.SetBackground(wxBrush(col
)); 
 418                     int x 
= (16 - bmp
.GetWidth())/2; 
 419                     int y 
= (16 - bmp
.GetHeight())/2; 
 420                     memDC
.DrawBitmap(bmp
, x
, y
, true); 
 421                     memDC
.SelectObject(wxNullBitmap
); 
 424                     tool
->SetNormalBitmap(b
); 
 430                     n 
= ::CommandBar_AddBitmap( (HWND
) GetHWND(), NULL
, (int) (HBITMAP
) bmpToUse
.GetHBITMAP(), 
 434                 button
.idCommand 
= tool
->GetId(); 
 437                 if ( tool
->IsEnabled() ) 
 438                     button
.fsState 
|= TBSTATE_ENABLED
; 
 439                 if ( tool
->IsToggled() ) 
 440                     button
.fsState 
|= TBSTATE_CHECKED
; 
 442                 switch ( tool
->GetKind() ) 
 445                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 449                             // the first item in the radio group is checked by 
 450                             // default to be consistent with wxGTK and the menu 
 452                             button
.fsState 
|= TBSTATE_CHECKED
; 
 461                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 465                         wxFAIL_MSG( _T("unexpected toolbar button kind") ); 
 469                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 474         if ( !::CommandBar_AddButtons( (HWND
) GetHWND(), 1, buttons 
) ) 
 476             wxFAIL_MSG( wxT("Could not add toolbar button.")); 
 479         lastWasRadio 
= isRadio
; 
 485 bool wxToolMenuBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id_
) 
 487     const int id 
= (signed short)id_
; 
 489     wxToolBarToolBase 
*tool 
= FindById(id
); 
 492         bool checked 
= false; 
 495             wxMenuItem 
*item 
= m_menuBar
->FindItem(id
); 
 496             if ( item 
&& item
->IsCheckable() ) 
 499                 checked 
= item
->IsChecked(); 
 503         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
); 
 504         event
.SetEventObject(this); 
 506         event
.SetInt(checked
); 
 508         return GetEventHandler()->ProcessEvent(event
); 
 511     if ( tool
->CanBeToggled() ) 
 513         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
 514         tool
->Toggle((state 
& TBSTATE_CHECKED
) != 0); 
 517     bool toggled 
= tool
->IsToggled(); 
 519     // avoid sending the event when a radio button is released, this is not 
 521     if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO 
|| toggled 
) 
 523         // OnLeftClick() can veto the button state change - for buttons which 
 524         // may be toggled only, of couse 
 525         if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
 529             tool
->SetToggle(toggled
); 
 531             ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0)); 
 538 WXLRESULT 
wxToolMenuBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 546             // we don't handle mouse moves, so always pass the message to 
 547             // wxControl::MSWWindowProc 
 548             HandleMouseMove(wParam
, lParam
); 
 555     return MSWDefWindowProc(nMsg
, wParam
, lParam
); 
 561 ////////////// For Smartphone 
 563 // ---------------------------------------------------------------------------- 
 565 // ---------------------------------------------------------------------------- 
 567 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
) 
 569 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 572 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 573                                          const wxString
& label
, 
 574                                          const wxBitmap
& bmpNormal
, 
 575                                          const wxBitmap
& bmpDisabled
, 
 577                                          wxObject 
*clientData
, 
 578                                          const wxString
& shortHelp
, 
 579                                          const wxString
& longHelp
) 
 581     return new wxToolBarToolBase(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 582                              clientData
, shortHelp
, longHelp
); 
 585 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 587     return new wxToolBarToolBase(this, control
); 
 590 bool wxToolBar::Create(wxWindow 
*parent
, 
 591                        wxWindowID 
WXUNUSED(id
), 
 592                        const wxPoint
& WXUNUSED(pos
), 
 593                        const wxSize
& WXUNUSED(size
), 
 595                        const wxString
& name
) 
 597     // TODO: we may need to make this a dummy hidden window to 
 598     // satisfy other parts of wxWidgets. 
 600     parent
->AddChild(this); 
 602     SetWindowStyle(style
); 
 608 // ---------------------------------------------------------------------------- 
 609 // adding/removing tools 
 610 // ---------------------------------------------------------------------------- 
 612 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 618 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 624 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) const 
 629 // ---------------------------------------------------------------------------- 
 631 // ---------------------------------------------------------------------------- 
 633 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(enable
)) 
 637 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 641 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 643     wxFAIL_MSG( _T("not implemented") ); 
 649 #endif // wxUSE_TOOLBAR