1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/tbarwce.cpp
3 // Purpose: wxToolBar for Windows CE
4 // Author: Julian Smart
7 // Copyright: (c) Julian Smart
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
26 // Use the WinCE-specific toolbar only if we're either compiling
27 // with a WinCE earlier than 4, or we wish to emulate a PocketPC-style UI
28 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (_WIN32_WCE < 400 || defined(__POCKETPC__) || defined(__SMARTPHONE__))
30 #include "wx/toolbar.h"
33 #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
34 #include "wx/dynarray.h"
38 #include "wx/settings.h"
39 #include "wx/bitmap.h"
40 #include "wx/dcmemory.h"
41 #include "wx/control.h"
44 #if !defined(__GNUWIN32__)
48 #include "wx/msw/private.h"
54 #if defined(WINCE_WITHOUT_COMMANDBAR)
56 #include "wx/msw/wince/resources.h"
58 #include "wx/msw/wince/missing.h"
60 #include "wx/msw/winundef.h"
62 #if !defined(__SMARTPHONE__)
64 ///////////// This implementation is for PocketPC.
65 ///////////// See later for the Smartphone dummy toolbar class.
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 IMPLEMENT_DYNAMIC_CLASS(wxToolMenuBar
, wxToolBar
)
73 BEGIN_EVENT_TABLE(wxToolMenuBar
, wxToolBar
)
76 // ----------------------------------------------------------------------------
78 // ----------------------------------------------------------------------------
80 class wxToolMenuBarTool
: public wxToolBarToolBase
83 wxToolMenuBarTool(wxToolBar
*tbar
,
85 const wxString
& label
,
86 const wxBitmap
& bmpNormal
,
87 const wxBitmap
& bmpDisabled
,
90 const wxString
& shortHelp
,
91 const wxString
& longHelp
)
92 : wxToolBarToolBase(tbar
, id
, label
, bmpNormal
, bmpDisabled
, kind
,
93 clientData
, shortHelp
, longHelp
)
99 wxToolMenuBarTool(wxToolBar
*tbar
, wxControl
*control
, const wxString
& label
)
100 : wxToolBarToolBase(tbar
, control
, label
)
106 virtual void SetLabel(const wxString
& label
)
108 if ( label
== m_label
)
111 wxToolBarToolBase::SetLabel(label
);
113 // we need to update the label shown in the toolbar because it has a
114 // pointer to the internal buffer of the old label
116 // TODO: use TB_SETBUTTONINFO
119 // set/get the number of separators which we use to cover the space used by
120 // a control in the toolbar
121 void SetSeparatorsCount(size_t count
) { m_nSepCount
= count
; }
122 size_t GetSeparatorsCount() const { return m_nSepCount
; }
124 void SetBitmapIndex(int idx
) { m_bitmapIndex
= idx
; }
125 int GetBitmapIndex() const { return m_bitmapIndex
; }
133 // ============================================================================
135 // ============================================================================
137 // ----------------------------------------------------------------------------
139 // ----------------------------------------------------------------------------
141 wxToolBarToolBase
*wxToolMenuBar::CreateTool(int id
,
142 const wxString
& label
,
143 const wxBitmap
& bmpNormal
,
144 const wxBitmap
& bmpDisabled
,
146 wxObject
*clientData
,
147 const wxString
& shortHelp
,
148 const wxString
& longHelp
)
150 return new wxToolMenuBarTool(this, id
, label
, bmpNormal
, bmpDisabled
, kind
,
151 clientData
, shortHelp
, longHelp
);
155 wxToolMenuBar::CreateTool(wxControl
*control
, const wxString
& label
)
157 return new wxToolMenuBarTool(this, control
, label
);
160 // ----------------------------------------------------------------------------
161 // wxToolBar construction
162 // ----------------------------------------------------------------------------
164 void wxToolMenuBar::Init()
172 bool wxToolMenuBar::Create(wxWindow
*parent
,
177 const wxString
& name
,
180 // common initialisation
181 if ( !CreateControl(parent
, id
, pos
, size
, style
, wxDefaultValidator
, name
) )
184 // MSW-specific initialisation
185 if ( !MSWCreateToolbar(pos
, size
, menuBar
) )
188 // set up the colors and fonts
189 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR
));
190 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT
));
195 bool wxToolMenuBar::MSWCreateToolbar(const wxPoint
& WXUNUSED(pos
),
196 const wxSize
& WXUNUSED(size
),
201 m_menuBar
->SetToolBar(this);
203 HWND hwndParent
= GetHwndOf(GetParent());
204 wxCHECK_MSG( hwndParent
, false, wxT("should have valid parent HWND") );
206 #if defined(WINCE_WITHOUT_COMMANDBAR)
207 // create the menubar.
208 WinStruct
<SHMENUBARINFO
> mbi
;
210 mbi
.hwndParent
= hwndParent
;
211 mbi
.nToolBarId
= wxIDM_SHMENU
;
212 mbi
.hInstRes
= wxGetInstance();
214 if ( !SHCreateMenuBar(&mbi
) )
216 wxFAIL_MSG( wxT("SHCreateMenuBar failed") );
220 SetHWND((WXHWND
) mbi
.hwndMB
);
222 HWND hWnd
= CommandBar_Create(wxGetInstance(), hwndParent
, GetId());
223 SetHWND((WXHWND
) hWnd
);
226 // install wxWidgets window proc for this window
235 void wxToolMenuBar::Recreate()
240 wxToolMenuBar::~wxToolMenuBar()
243 GetMenuBar()->SetToolBar(NULL
);
246 // Return HMENU for the menu associated with the commandbar
247 WXHMENU
wxToolMenuBar::GetHMenu()
249 #if !defined(__HANDHELDPC__)
252 return (WXHMENU
)::SendMessage(GetHwnd(), SHCMBM_GETMENU
, 0, 0);
259 // ----------------------------------------------------------------------------
260 // adding/removing tools
261 // ----------------------------------------------------------------------------
263 bool wxToolMenuBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
265 // nothing special to do here - we really create the toolbar buttons in
272 bool wxToolMenuBar::DoDeleteTool(size_t pos
, wxToolBarToolBase
*tool
)
274 // Skip over the menus
276 pos
+= GetMenuBar()->GetMenuCount();
278 // the main difficulty we have here is with the controls in the toolbars:
279 // as we (sometimes) use several separators to cover up the space used by
280 // them, the indices are not the same for us and the toolbar
282 // first determine the position of the first button to delete: it may be
283 // different from pos if we use several separators to cover the space used
285 wxToolBarToolsList::compatibility_iterator node
;
286 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
288 wxToolBarToolBase
*tool2
= node
->GetData();
291 // let node point to the next node in the list
292 node
= node
->GetNext();
297 if ( tool2
->IsControl() )
299 pos
+= ((wxToolMenuBarTool
*)tool2
)->GetSeparatorsCount() - 1;
303 // now determine the number of buttons to delete and the area taken by them
304 size_t nButtonsToDelete
= 1;
306 // get the size of the button we're going to delete
308 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT
, pos
, (LPARAM
)&r
) )
310 wxLogLastError(wxT("TB_GETITEMRECT"));
313 int width
= r
.right
- r
.left
;
315 if ( tool
->IsControl() )
317 nButtonsToDelete
= ((wxToolMenuBarTool
*)tool
)->GetSeparatorsCount();
319 width
*= nButtonsToDelete
;
322 // do delete all buttons
323 m_nButtons
-= nButtonsToDelete
;
324 while ( nButtonsToDelete
-- > 0 )
326 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, pos
, 0) )
328 wxLogLastError(wxT("TB_DELETEBUTTON"));
336 // and finally reposition all the controls after this button (the toolbar
337 // takes care of all normal items)
338 for ( /* node -> first after deleted */ ; node
; node
= node
->GetNext() )
340 wxToolBarToolBase
*tool2
= node
->GetData();
341 if ( tool2
->IsControl() )
344 wxControl
*control
= tool2
->GetControl();
345 control
->GetPosition(&x
, NULL
);
346 control
->Move(x
- width
, wxDefaultCoord
);
353 bool wxToolMenuBar::Realize()
355 const size_t nTools
= GetToolsCount();
363 // delete all old buttons, if any
364 for ( size_t pos
= 0; pos
< m_nButtons
; pos
++ )
366 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON
, 0, 0) )
368 wxLogDebug(wxT("TB_DELETEBUTTON failed"));
373 bool lastWasRadio
= false;
374 wxToolBarToolsList::compatibility_iterator node
;
375 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
377 wxToolMenuBarTool
*tool
= (wxToolMenuBarTool
*) node
->GetData();
379 TBBUTTON buttons
[1] ;
381 TBBUTTON
& button
= buttons
[0];
383 wxZeroMemory(button
);
385 bool isRadio
= false;
386 switch ( tool
->GetStyle() )
388 case wxTOOL_STYLE_CONTROL
:
389 button
.idCommand
= tool
->GetId();
390 // fall through: create just a separator too
391 // TODO: controls are not yet supported on wxToolMenuBar.
393 case wxTOOL_STYLE_SEPARATOR
:
394 button
.fsState
= TBSTATE_ENABLED
;
395 button
.fsStyle
= TBSTYLE_SEP
;
398 case wxTOOL_STYLE_BUTTON
:
400 if ( HasFlag(wxTB_TEXT
) )
402 const wxString
& label
= tool
->GetLabel();
403 if ( !label
.empty() )
405 button
.iString
= (int) wxMSW_CONV_LPCTSTR(label
);
409 const wxBitmap
& bmp
= tool
->GetNormalBitmap();
411 wxBitmap bmpToUse
= bmp
;
413 if (bmp
.GetWidth() < 16 || bmp
.GetHeight() < 16 || bmp
.GetMask() != NULL
)
417 memDC
.SelectObject(b
);
418 wxColour col
= wxColour(192,192,192);
419 memDC
.SetBackground(wxBrush(col
));
421 int x
= (16 - bmp
.GetWidth())/2;
422 int y
= (16 - bmp
.GetHeight())/2;
423 memDC
.DrawBitmap(bmp
, x
, y
, true);
424 memDC
.SelectObject(wxNullBitmap
);
427 tool
->SetNormalBitmap(b
);
431 if ( bmpToUse
.IsOk() )
433 n
= ::CommandBar_AddBitmap( (HWND
) GetHWND(), NULL
, (int) (HBITMAP
) bmpToUse
.GetHBITMAP(),
437 button
.idCommand
= tool
->GetId();
440 if ( tool
->IsEnabled() )
441 button
.fsState
|= TBSTATE_ENABLED
;
442 if ( tool
->IsToggled() )
443 button
.fsState
|= TBSTATE_CHECKED
;
445 switch ( tool
->GetKind() )
448 button
.fsStyle
= TBSTYLE_CHECKGROUP
;
452 // the first item in the radio group is checked by
453 // default to be consistent with wxGTK and the menu
455 button
.fsState
|= TBSTATE_CHECKED
;
464 button
.fsStyle
= TBSTYLE_CHECK
;
468 wxFAIL_MSG( wxT("unexpected toolbar button kind") );
472 button
.fsStyle
= TBSTYLE_BUTTON
;
477 if ( !::CommandBar_AddButtons( (HWND
) GetHWND(), 1, buttons
) )
479 wxFAIL_MSG( wxT("Could not add toolbar button."));
482 lastWasRadio
= isRadio
;
488 bool wxToolMenuBar::MSWCommand(WXUINT
WXUNUSED(cmd
), WXWORD id_
)
490 const int id
= (signed short)id_
;
492 wxToolBarToolBase
*tool
= FindById(id
);
495 bool checked
= false;
498 wxMenuItem
*item
= m_menuBar
->FindItem(id
);
499 if ( item
&& item
->IsCheckable() )
502 checked
= item
->IsChecked();
506 wxCommandEvent
event(wxEVT_MENU
);
507 event
.SetEventObject(this);
509 event
.SetInt(checked
);
511 return GetEventHandler()->ProcessEvent(event
);
514 if ( tool
->CanBeToggled() )
516 LRESULT state
= ::SendMessage(GetHwnd(), TB_GETSTATE
, id
, 0);
517 tool
->Toggle((state
& TBSTATE_CHECKED
) != 0);
520 bool toggled
= tool
->IsToggled();
522 // avoid sending the event when a radio button is released, this is not
524 if ( !tool
->CanBeToggled() || tool
->GetKind() != wxITEM_RADIO
|| toggled
)
526 // OnLeftClick() can veto the button state change - for buttons which
527 // may be toggled only, of course.
528 if ( !OnLeftClick((int)id
, toggled
) && tool
->CanBeToggled() )
532 tool
->SetToggle(toggled
);
534 ::SendMessage(GetHwnd(), TB_CHECKBUTTON
, id
, MAKELONG(toggled
, 0));
541 WXLRESULT
wxToolMenuBar::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
549 // we don't handle mouse moves, so always pass the message to
550 // wxControl::MSWWindowProc
551 HandleMouseMove(wParam
, lParam
);
558 return MSWDefWindowProc(nMsg
, wParam
, lParam
);
564 ////////////// For Smartphone
566 // ----------------------------------------------------------------------------
568 // ----------------------------------------------------------------------------
570 IMPLEMENT_DYNAMIC_CLASS(wxToolBar
, wxToolBarBase
)
572 BEGIN_EVENT_TABLE(wxToolBar
, wxToolBarBase
)
575 wxToolBarToolBase
*wxToolBar::CreateTool(int id
,
576 const wxString
& label
,
577 const wxBitmap
& bmpNormal
,
578 const wxBitmap
& bmpDisabled
,
580 wxObject
*clientData
,
581 const wxString
& shortHelp
,
582 const wxString
& longHelp
)
584 return new wxToolBarToolBase(this, id
, label
, bmpNormal
, bmpDisabled
, kind
,
585 clientData
, shortHelp
, longHelp
);
588 wxToolBarToolBase
*wxToolBar::CreateTool(wxControl
*control
)
590 return new wxToolBarToolBase(this, control
);
593 bool wxToolBar::Create(wxWindow
*parent
,
594 wxWindowID
WXUNUSED(id
),
595 const wxPoint
& WXUNUSED(pos
),
596 const wxSize
& WXUNUSED(size
),
598 const wxString
& name
)
600 // TODO: we may need to make this a dummy hidden window to
601 // satisfy other parts of wxWidgets.
603 parent
->AddChild(this);
605 SetWindowStyle(style
);
611 // ----------------------------------------------------------------------------
612 // adding/removing tools
613 // ----------------------------------------------------------------------------
615 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
621 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos
), wxToolBarToolBase
*tool
)
627 wxToolBarToolBase
*wxToolBar::FindToolForPosition(wxCoord
WXUNUSED(x
), wxCoord
WXUNUSED(y
)) const
632 // ----------------------------------------------------------------------------
634 // ----------------------------------------------------------------------------
636 void wxToolBar::DoEnableTool(wxToolBarToolBase
*WXUNUSED(tool
), bool WXUNUSED(enable
))
640 void wxToolBar::DoToggleTool(wxToolBarToolBase
*WXUNUSED(tool
), bool WXUNUSED(toggle
))
644 void wxToolBar::DoSetToggle(wxToolBarToolBase
*WXUNUSED(tool
), bool WXUNUSED(toggle
))
646 wxFAIL_MSG( wxT("not implemented") );
652 #endif // wxUSE_TOOLBAR