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, wxT("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( wxT("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     // Skip over the menus 
 277         pos 
+= GetMenuBar()->GetMenuCount(); 
 279     // the main difficulty we have here is with the controls in the toolbars: 
 280     // as we (sometimes) use several separators to cover up the space used by 
 281     // them, the indices are not the same for us and the toolbar 
 283     // first determine the position of the first button to delete: it may be 
 284     // different from pos if we use several separators to cover the space used 
 286     wxToolBarToolsList::compatibility_iterator node
; 
 287     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 289         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 292             // let node point to the next node in the list 
 293             node 
= node
->GetNext(); 
 298         if ( tool2
->IsControl() ) 
 300             pos 
+= ((wxToolMenuBarTool 
*)tool2
)->GetSeparatorsCount() - 1; 
 304     // now determine the number of buttons to delete and the area taken by them 
 305     size_t nButtonsToDelete 
= 1; 
 307     // get the size of the button we're going to delete 
 309     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) ) 
 311         wxLogLastError(wxT("TB_GETITEMRECT")); 
 314     int width 
= r
.right 
- r
.left
; 
 316     if ( tool
->IsControl() ) 
 318         nButtonsToDelete 
= ((wxToolMenuBarTool 
*)tool
)->GetSeparatorsCount(); 
 320         width 
*= nButtonsToDelete
; 
 323     // do delete all buttons 
 324     m_nButtons 
-= nButtonsToDelete
; 
 325     while ( nButtonsToDelete
-- > 0 ) 
 327         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) ) 
 329             wxLogLastError(wxT("TB_DELETEBUTTON")); 
 337     // and finally reposition all the controls after this button (the toolbar 
 338     // takes care of all normal items) 
 339     for ( /* node -> first after deleted */ ; node
; node 
= node
->GetNext() ) 
 341         wxToolBarToolBase 
*tool2 
= node
->GetData(); 
 342         if ( tool2
->IsControl() ) 
 345             wxControl 
*control 
= tool2
->GetControl(); 
 346             control
->GetPosition(&x
, NULL
); 
 347             control
->Move(x 
- width
, wxDefaultCoord
); 
 354 bool wxToolMenuBar::Realize() 
 356     const size_t nTools 
= GetToolsCount(); 
 364     // delete all old buttons, if any 
 365     for ( size_t pos 
= 0; pos 
< m_nButtons
; pos
++ ) 
 367         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) ) 
 369             wxLogDebug(wxT("TB_DELETEBUTTON failed")); 
 374     bool lastWasRadio 
= false; 
 375     wxToolBarToolsList::Node
* node
; 
 376     for ( node 
= m_tools
.GetFirst(); node
; node 
= node
->GetNext() ) 
 378         wxToolMenuBarTool 
*tool 
= (wxToolMenuBarTool
*) node
->GetData(); 
 380         TBBUTTON buttons
[1] ; 
 382         TBBUTTON
& button 
= buttons
[0]; 
 384         wxZeroMemory(button
); 
 386         bool isRadio 
= false; 
 387         switch ( tool
->GetStyle() ) 
 389             case wxTOOL_STYLE_CONTROL
: 
 390                 button
.idCommand 
= tool
->GetId(); 
 391                 // fall through: create just a separator too 
 392                 // TODO: controls are not yet supported on wxToolMenuBar. 
 394             case wxTOOL_STYLE_SEPARATOR
: 
 395                 button
.fsState 
= TBSTATE_ENABLED
; 
 396                 button
.fsStyle 
= TBSTYLE_SEP
; 
 399             case wxTOOL_STYLE_BUTTON
: 
 401                 if ( HasFlag(wxTB_TEXT
) ) 
 403                     const wxString
& label 
= tool
->GetLabel(); 
 404                     if ( !label
.empty() ) 
 406                         button
.iString 
= (int)label
.wx_str(); 
 410                 const wxBitmap
& bmp 
= tool
->GetNormalBitmap(); 
 412                 wxBitmap bmpToUse 
= bmp
; 
 414                 if (bmp
.GetWidth() < 16 || bmp
.GetHeight() < 16 || bmp
.GetMask() != NULL
) 
 418                     memDC
.SelectObject(b
); 
 419                     wxColour col 
= wxColour(192,192,192); 
 420                     memDC
.SetBackground(wxBrush(col
)); 
 422                     int x 
= (16 - bmp
.GetWidth())/2; 
 423                     int y 
= (16 - bmp
.GetHeight())/2; 
 424                     memDC
.DrawBitmap(bmp
, x
, y
, true); 
 425                     memDC
.SelectObject(wxNullBitmap
); 
 428                     tool
->SetNormalBitmap(b
); 
 432                 if ( bmpToUse
.IsOk() ) 
 434                     n 
= ::CommandBar_AddBitmap( (HWND
) GetHWND(), NULL
, (int) (HBITMAP
) bmpToUse
.GetHBITMAP(), 
 438                 button
.idCommand 
= tool
->GetId(); 
 441                 if ( tool
->IsEnabled() ) 
 442                     button
.fsState 
|= TBSTATE_ENABLED
; 
 443                 if ( tool
->IsToggled() ) 
 444                     button
.fsState 
|= TBSTATE_CHECKED
; 
 446                 switch ( tool
->GetKind() ) 
 449                         button
.fsStyle 
= TBSTYLE_CHECKGROUP
; 
 453                             // the first item in the radio group is checked by 
 454                             // default to be consistent with wxGTK and the menu 
 456                             button
.fsState 
|= TBSTATE_CHECKED
; 
 465                         button
.fsStyle 
= TBSTYLE_CHECK
; 
 469                         wxFAIL_MSG( wxT("unexpected toolbar button kind") ); 
 473                         button
.fsStyle 
= TBSTYLE_BUTTON
; 
 478         if ( !::CommandBar_AddButtons( (HWND
) GetHWND(), 1, buttons 
) ) 
 480             wxFAIL_MSG( wxT("Could not add toolbar button.")); 
 483         lastWasRadio 
= isRadio
; 
 489 bool wxToolMenuBar::MSWCommand(WXUINT 
WXUNUSED(cmd
), WXWORD id_
) 
 491     const int id 
= (signed short)id_
; 
 493     wxToolBarToolBase 
*tool 
= FindById(id
); 
 496         bool checked 
= false; 
 499             wxMenuItem 
*item 
= m_menuBar
->FindItem(id
); 
 500             if ( item 
&& item
->IsCheckable() ) 
 503                 checked 
= item
->IsChecked(); 
 507         wxCommandEvent 
event(wxEVT_COMMAND_MENU_SELECTED
); 
 508         event
.SetEventObject(this); 
 510         event
.SetInt(checked
); 
 512         return GetEventHandler()->ProcessEvent(event
); 
 515     if ( tool
->CanBeToggled() ) 
 517         LRESULT state 
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0); 
 518         tool
->Toggle((state 
& TBSTATE_CHECKED
) != 0); 
 521     bool toggled 
= tool
->IsToggled(); 
 523     // avoid sending the event when a radio button is released, this is not 
 525     if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO 
|| toggled 
) 
 527         // OnLeftClick() can veto the button state change - for buttons which 
 528         // may be toggled only, of course. 
 529         if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() ) 
 533             tool
->SetToggle(toggled
); 
 535             ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0)); 
 542 WXLRESULT 
wxToolMenuBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
) 
 550             // we don't handle mouse moves, so always pass the message to 
 551             // wxControl::MSWWindowProc 
 552             HandleMouseMove(wParam
, lParam
); 
 559     return MSWDefWindowProc(nMsg
, wParam
, lParam
); 
 565 ////////////// For Smartphone 
 567 // ---------------------------------------------------------------------------- 
 569 // ---------------------------------------------------------------------------- 
 571 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
) 
 573 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
) 
 576 wxToolBarToolBase 
*wxToolBar::CreateTool(int id
, 
 577                                          const wxString
& label
, 
 578                                          const wxBitmap
& bmpNormal
, 
 579                                          const wxBitmap
& bmpDisabled
, 
 581                                          wxObject 
*clientData
, 
 582                                          const wxString
& shortHelp
, 
 583                                          const wxString
& longHelp
) 
 585     return new wxToolBarToolBase(this, id
, label
, bmpNormal
, bmpDisabled
, kind
, 
 586                              clientData
, shortHelp
, longHelp
); 
 589 wxToolBarToolBase 
*wxToolBar::CreateTool(wxControl 
*control
) 
 591     return new wxToolBarToolBase(this, control
); 
 594 bool wxToolBar::Create(wxWindow 
*parent
, 
 595                        wxWindowID 
WXUNUSED(id
), 
 596                        const wxPoint
& WXUNUSED(pos
), 
 597                        const wxSize
& WXUNUSED(size
), 
 599                        const wxString
& name
) 
 601     // TODO: we may need to make this a dummy hidden window to 
 602     // satisfy other parts of wxWidgets. 
 604     parent
->AddChild(this); 
 606     SetWindowStyle(style
); 
 612 // ---------------------------------------------------------------------------- 
 613 // adding/removing tools 
 614 // ---------------------------------------------------------------------------- 
 616 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 622 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase 
*tool
) 
 628 wxToolBarToolBase 
*wxToolBar::FindToolForPosition(wxCoord 
WXUNUSED(x
), wxCoord 
WXUNUSED(y
)) const 
 633 // ---------------------------------------------------------------------------- 
 635 // ---------------------------------------------------------------------------- 
 637 void wxToolBar::DoEnableTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(enable
)) 
 641 void wxToolBar::DoToggleTool(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 645 void wxToolBar::DoSetToggle(wxToolBarToolBase 
*WXUNUSED(tool
), bool WXUNUSED(toggle
)) 
 647     wxFAIL_MSG( wxT("not implemented") ); 
 653 #endif // wxUSE_TOOLBAR