1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/wince/tbarwce.cpp
3 // Purpose:     wxToolBar for Windows CE
4 // Author:      Julian Smart
5 // Modified by:
6 // Created:     2003-07-12
7 // RCS-ID:      $Id: tbarwce.cpp 61236 2009-06-28 17:01:27Z JS $
8 // Copyright:   (c) Julian Smart
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // ============================================================================
13 // declarations
14 // ============================================================================
15 
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22 
23 #ifdef __BORLANDC__
24     #pragma hdrstop
25 #endif
26 
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__))
30 
31 #include "wx/toolbar.h"
32 
33 #ifndef WX_PRECOMP
34     #include "wx/msw/wrapcctl.h" // include <commctrl.h> "properly"
35     #include "wx/dynarray.h"
36     #include "wx/frame.h"
37     #include "wx/log.h"
38     #include "wx/intl.h"
39     #include "wx/settings.h"
40     #include "wx/bitmap.h"
41     #include "wx/dcmemory.h"
42     #include "wx/control.h"
43 #endif
44 
45 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
46     #include "malloc.h"
47 #endif
48 
49 #include "wx/msw/private.h"
50 #include <windows.h>
51 #include <windowsx.h>
52 #include <tchar.h>
53 #include <ole2.h>
54 #include <shellapi.h>
55 #if defined(WINCE_WITHOUT_COMMANDBAR)
56   #include <aygshell.h>
57 #endif
58 #include "wx/msw/wince/missing.h"
59 
60 #include "wx/msw/winundef.h"
61 
62 #if !defined(__SMARTPHONE__)
63 
64 ///////////// This implementation is for PocketPC.
65 ///////////// See later for the Smartphone dummy toolbar class.
66 
67 // ----------------------------------------------------------------------------
68 // Event table
69 // ----------------------------------------------------------------------------
70 
71 IMPLEMENT_DYNAMIC_CLASS(wxToolMenuBar, wxToolBar)
72 
73 BEGIN_EVENT_TABLE(wxToolMenuBar, wxToolBar)
74 END_EVENT_TABLE()
75 
76 // ----------------------------------------------------------------------------
77 // private classes
78 // ----------------------------------------------------------------------------
79 
80 class wxToolMenuBarTool : public wxToolBarToolBase
81 {
82 public:
wxToolMenuBarTool(wxToolBar * tbar,int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpDisabled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)83     wxToolMenuBarTool(wxToolBar *tbar,
84                   int id,
85                   const wxString& label,
86                   const wxBitmap& bmpNormal,
87                   const wxBitmap& bmpDisabled,
88                   wxItemKind kind,
89                   wxObject *clientData,
90                   const wxString& shortHelp,
91                   const wxString& longHelp)
92         : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
93                             clientData, shortHelp, longHelp)
94     {
95         m_nSepCount = 0;
96         m_bitmapIndex = -1;
97     }
98 
wxToolMenuBarTool(wxToolBar * tbar,wxControl * control)99     wxToolMenuBarTool(wxToolBar *tbar, wxControl *control)
100         : wxToolBarToolBase(tbar, control)
101     {
102         m_nSepCount = 1;
103         m_bitmapIndex = -1;
104     }
105 
SetLabel(const wxString & label)106     virtual void SetLabel(const wxString& label)
107     {
108         if ( label == m_label )
109             return;
110 
111         wxToolBarToolBase::SetLabel(label);
112 
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
115         //
116         // TODO: use TB_SETBUTTONINFO
117     }
118 
119     // set/get the number of separators which we use to cover the space used by
120     // a control in the toolbar
SetSeparatorsCount(size_t count)121     void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
GetSeparatorsCount() const122     size_t GetSeparatorsCount() const { return m_nSepCount; }
123 
SetBitmapIndex(int idx)124     void SetBitmapIndex(int idx) { m_bitmapIndex = idx; }
GetBitmapIndex() const125     int GetBitmapIndex() const { return m_bitmapIndex; }
126 
127 private:
128     size_t m_nSepCount;
129     int m_bitmapIndex;
130 };
131 
132 
133 // ============================================================================
134 // implementation
135 // ============================================================================
136 
137 // ----------------------------------------------------------------------------
138 // wxToolBarTool
139 // ----------------------------------------------------------------------------
140 
CreateTool(int id,const wxString & label,const wxBitmap & bmpNormal,const wxBitmap & bmpDisabled,wxItemKind kind,wxObject * clientData,const wxString & shortHelp,const wxString & longHelp)141 wxToolBarToolBase *wxToolMenuBar::CreateTool(int id,
142                                          const wxString& label,
143                                          const wxBitmap& bmpNormal,
144                                          const wxBitmap& bmpDisabled,
145                                          wxItemKind kind,
146                                          wxObject *clientData,
147                                          const wxString& shortHelp,
148                                          const wxString& longHelp)
149 {
150     return new wxToolMenuBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
151                              clientData, shortHelp, longHelp);
152 }
153 
CreateTool(wxControl * control)154 wxToolBarToolBase *wxToolMenuBar::CreateTool(wxControl *control)
155 {
156     return new wxToolMenuBarTool(this, control);
157 }
158 
159 // ----------------------------------------------------------------------------
160 // wxToolBar construction
161 // ----------------------------------------------------------------------------
162 
Init()163 void wxToolMenuBar::Init()
164 {
165     wxToolBar::Init();
166 
167     m_nButtons = 0;
168     m_menuBar = NULL;
169 }
170 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxString & name,wxMenuBar * menuBar)171 bool wxToolMenuBar::Create(wxWindow *parent,
172                        wxWindowID id,
173                        const wxPoint& pos,
174                        const wxSize& size,
175                        long style,
176                        const wxString& name,
177                        wxMenuBar* menuBar)
178 {
179     // common initialisation
180     if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
181         return false;
182 
183     // MSW-specific initialisation
184     if ( !MSWCreateToolbar(pos, size, menuBar) )
185         return false;
186 
187     // set up the colors and fonts
188     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
189     SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
190 
191     return true;
192 }
193 
MSWCreateToolbar(const wxPoint & WXUNUSED (pos),const wxSize & WXUNUSED (size),wxMenuBar * menuBar)194 bool wxToolMenuBar::MSWCreateToolbar(const wxPoint& WXUNUSED(pos), const wxSize& WXUNUSED(size), wxMenuBar* menuBar)
195 {
196     SetMenuBar(menuBar);
197     if (m_menuBar)
198         m_menuBar->SetToolBar(this);
199 
200 #if defined(WINCE_WITHOUT_COMMANDBAR)
201     // Create the menubar.
202     SHMENUBARINFO mbi;
203 
204     memset (&mbi, 0, sizeof (SHMENUBARINFO));
205     mbi.cbSize     = sizeof (SHMENUBARINFO);
206     mbi.hwndParent = (HWND) GetParent()->GetHWND();
207 #ifdef __SMARTPHONE__
208     mbi.nToolBarId = 5002;
209 #else
210     mbi.nToolBarId = 5000;
211 #endif
212     mbi.nBmpId     = 0;
213     mbi.cBmpImages = 0;
214     mbi.dwFlags = 0 ; // SHCMBF_EMPTYBAR;
215     mbi.hInstRes = wxGetInstance();
216 
217     if (!SHCreateMenuBar(&mbi))
218     {
219         wxFAIL_MSG( _T("SHCreateMenuBar failed") );
220         return false;
221     }
222 
223     SetHWND((WXHWND) mbi.hwndMB);
224 #else
225     HWND hWnd = CommandBar_Create(wxGetInstance(), (HWND) GetParent()->GetHWND(), GetId());
226     SetHWND((WXHWND) hWnd);
227 #endif
228 
229     // install wxWidgets window proc for this window
230     SubclassWin(m_hWnd);
231 
232     if (menuBar)
233         menuBar->Create();
234 
235     return true;
236 }
237 
Recreate()238 void wxToolMenuBar::Recreate()
239 {
240     // TODO
241 }
242 
~wxToolMenuBar()243 wxToolMenuBar::~wxToolMenuBar()
244 {
245     if (GetMenuBar())
246         GetMenuBar()->SetToolBar(NULL);
247 }
248 
249 // Return HMENU for the menu associated with the commandbar
GetHMenu()250 WXHMENU wxToolMenuBar::GetHMenu()
251 {
252 #if defined(__HANDHELDPC__)
253     return 0;
254 #else
255     if (GetHWND())
256     {
257         return (WXHMENU) (HMENU)::SendMessage((HWND) GetHWND(), SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0);
258     }
259     else
260         return 0;
261 #endif
262 }
263 
264 // ----------------------------------------------------------------------------
265 // adding/removing tools
266 // ----------------------------------------------------------------------------
267 
DoInsertTool(size_t WXUNUSED (pos),wxToolBarToolBase * tool)268 bool wxToolMenuBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
269 {
270     // nothing special to do here - we really create the toolbar buttons in
271     // Realize() later
272     tool->Attach(this);
273 
274     return true;
275 }
276 
DoDeleteTool(size_t pos,wxToolBarToolBase * tool)277 bool wxToolMenuBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
278 {
279     // Skip over the menus
280     if (GetMenuBar())
281         pos += GetMenuBar()->GetMenuCount();
282 
283     // the main difficulty we have here is with the controls in the toolbars:
284     // as we (sometimes) use several separators to cover up the space used by
285     // them, the indices are not the same for us and the toolbar
286 
287     // first determine the position of the first button to delete: it may be
288     // different from pos if we use several separators to cover the space used
289     // by a control
290     wxToolBarToolsList::compatibility_iterator node;
291     for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
292     {
293         wxToolBarToolBase *tool2 = node->GetData();
294         if ( tool2 == tool )
295         {
296             // let node point to the next node in the list
297             node = node->GetNext();
298 
299             break;
300         }
301 
302         if ( tool2->IsControl() )
303         {
304             pos += ((wxToolMenuBarTool *)tool2)->GetSeparatorsCount() - 1;
305         }
306     }
307 
308     // now determine the number of buttons to delete and the area taken by them
309     size_t nButtonsToDelete = 1;
310 
311     // get the size of the button we're going to delete
312     RECT r;
313     if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
314     {
315         wxLogLastError(_T("TB_GETITEMRECT"));
316     }
317 
318     int width = r.right - r.left;
319 
320     if ( tool->IsControl() )
321     {
322         nButtonsToDelete = ((wxToolMenuBarTool *)tool)->GetSeparatorsCount();
323 
324         width *= nButtonsToDelete;
325     }
326 
327     // do delete all buttons
328     m_nButtons -= nButtonsToDelete;
329     while ( nButtonsToDelete-- > 0 )
330     {
331         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
332         {
333             wxLogLastError(wxT("TB_DELETEBUTTON"));
334 
335             return false;
336         }
337     }
338 
339     tool->Detach();
340 
341     // and finally reposition all the controls after this button (the toolbar
342     // takes care of all normal items)
343     for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
344     {
345         wxToolBarToolBase *tool2 = node->GetData();
346         if ( tool2->IsControl() )
347         {
348             int x;
349             wxControl *control = tool2->GetControl();
350             control->GetPosition(&x, NULL);
351             control->Move(x - width, wxDefaultCoord);
352         }
353     }
354 
355     return true;
356 }
357 
Realize()358 bool wxToolMenuBar::Realize()
359 {
360     const size_t nTools = GetToolsCount();
361     if ( nTools == 0 )
362     {
363         // nothing to do
364         return true;
365     }
366 
367 #if 0
368     // delete all old buttons, if any
369     for ( size_t pos = 0; pos < m_nButtons; pos++ )
370     {
371         if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
372         {
373             wxLogDebug(wxT("TB_DELETEBUTTON failed"));
374         }
375     }
376 #endif // 0
377 
378     bool lastWasRadio = false;
379     wxToolBarToolsList::Node* node;
380     for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
381     {
382         wxToolMenuBarTool *tool = (wxToolMenuBarTool*) node->GetData();
383 
384         TBBUTTON buttons[1] ;
385 
386         TBBUTTON& button = buttons[0];
387 
388         wxZeroMemory(button);
389 
390         bool isRadio = false;
391         switch ( tool->GetStyle() )
392         {
393             case wxTOOL_STYLE_CONTROL:
394                 button.idCommand = tool->GetId();
395                 // fall through: create just a separator too
396                 // TODO: controls are not yet supported on wxToolMenuBar.
397 
398             case wxTOOL_STYLE_SEPARATOR:
399                 button.fsState = TBSTATE_ENABLED;
400                 button.fsStyle = TBSTYLE_SEP;
401                 break;
402 
403             case wxTOOL_STYLE_BUTTON:
404 
405                 if ( HasFlag(wxTB_TEXT) )
406                 {
407                     const wxString& label = tool->GetLabel();
408                     if ( !label.empty() )
409                     {
410                         button.iString = (int)label.c_str();
411                     }
412                 }
413 
414                 const wxBitmap& bmp = tool->GetNormalBitmap();
415 
416                 wxBitmap bmpToUse = bmp;
417 
418                 if (bmp.GetWidth() < 16 || bmp.GetHeight() < 16 || bmp.GetMask() != NULL)
419                 {
420                     wxMemoryDC memDC;
421                     wxBitmap b(16,16);
422                     memDC.SelectObject(b);
423                     wxColour col = wxColour(192,192,192);
424                     memDC.SetBackground(wxBrush(col));
425                     memDC.Clear();
426                     int x = (16 - bmp.GetWidth())/2;
427                     int y = (16 - bmp.GetHeight())/2;
428                     memDC.DrawBitmap(bmp, x, y, true);
429                     memDC.SelectObject(wxNullBitmap);
430 
431                     bmpToUse = b;
432                     tool->SetNormalBitmap(b);
433                 }
434 
435                 int n = 0;
436                 if ( bmpToUse.Ok() )
437                 {
438                     n = ::CommandBar_AddBitmap( (HWND) GetHWND(), NULL, (int) (HBITMAP) bmpToUse.GetHBITMAP(),
439                                                     1, 16, 16 );
440                 }
441 
442                 button.idCommand = tool->GetId();
443                 button.iBitmap = n;
444 
445                 if ( tool->IsEnabled() )
446                     button.fsState |= TBSTATE_ENABLED;
447                 if ( tool->IsToggled() )
448                     button.fsState |= TBSTATE_CHECKED;
449 
450                 switch ( tool->GetKind() )
451                 {
452                     case wxITEM_RADIO:
453                         button.fsStyle = TBSTYLE_CHECKGROUP;
454 
455                         if ( !lastWasRadio )
456                         {
457                             // the first item in the radio group is checked by
458                             // default to be consistent with wxGTK and the menu
459                             // radio items
460                             button.fsState |= TBSTATE_CHECKED;
461 
462                             tool->Toggle(true);
463                         }
464 
465                         isRadio = true;
466                         break;
467 
468                     case wxITEM_CHECK:
469                         button.fsStyle = TBSTYLE_CHECK;
470                         break;
471 
472                     default:
473                         wxFAIL_MSG( _T("unexpected toolbar button kind") );
474                         // fall through
475 
476                     case wxITEM_NORMAL:
477                         button.fsStyle = TBSTYLE_BUTTON;
478                 }
479                 break;
480         }
481 
482         if ( !::CommandBar_AddButtons( (HWND) GetHWND(), 1, buttons ) )
483         {
484             wxFAIL_MSG( wxT("Could not add toolbar button."));
485         }
486 
487         lastWasRadio = isRadio;
488     }
489 
490     return true;
491 }
492 
MSWCommand(WXUINT WXUNUSED (cmd),WXWORD id)493 bool wxToolMenuBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
494 {
495     wxToolBarToolBase *tool = FindById((int)id);
496     if ( !tool )
497     {
498         bool checked = false;
499         if ( m_menuBar )
500         {
501             wxMenuItem *item = m_menuBar->FindItem(id);
502             if ( item && item->IsCheckable() )
503             {
504                 item->Toggle();
505                 checked = item->IsChecked();
506             }
507         }
508 
509         wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
510         event.SetEventObject(this);
511         event.SetId(id);
512         event.SetInt(checked);
513 
514         return GetEventHandler()->ProcessEvent(event);
515     }
516 
517     if ( tool->CanBeToggled() )
518     {
519         LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
520         tool->Toggle((state & TBSTATE_CHECKED) != 0);
521     }
522 
523     bool toggled = tool->IsToggled();
524 
525     // avoid sending the event when a radio button is released, this is not
526     // interesting
527     if ( !tool->CanBeToggled() || tool->GetKind() != wxITEM_RADIO || toggled )
528     {
529         // OnLeftClick() can veto the button state change - for buttons which
530         // may be toggled only, of couse
531         if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
532         {
533             // revert back
534             toggled = !toggled;
535             tool->SetToggle(toggled);
536 
537             ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
538         }
539     }
540 
541     return true;
542 }
543 
MSWWindowProc(WXUINT nMsg,WXWPARAM wParam,WXLPARAM lParam)544 WXLRESULT wxToolMenuBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
545 {
546     switch ( nMsg )
547     {
548         case WM_SIZE:
549             break;
550 
551         case WM_MOUSEMOVE:
552             // we don't handle mouse moves, so always pass the message to
553             // wxControl::MSWWindowProc
554             HandleMouseMove(wParam, lParam);
555             break;
556 
557         case WM_PAINT:
558             break;
559     }
560 
561     return MSWDefWindowProc(nMsg, wParam, lParam);
562 }
563 
564 
565 #else
566 
567 ////////////// For Smartphone
568 
569 // ----------------------------------------------------------------------------
570 // Event table
571 // ----------------------------------------------------------------------------
572 
IMPLEMENT_DYNAMIC_CLASS(wxToolBar,wxToolBarBase)573 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
574 
575 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
576 END_EVENT_TABLE()
577 
578 wxToolBarToolBase *wxToolBar::CreateTool(int id,
579                                          const wxString& label,
580                                          const wxBitmap& bmpNormal,
581                                          const wxBitmap& bmpDisabled,
582                                          wxItemKind kind,
583                                          wxObject *clientData,
584                                          const wxString& shortHelp,
585                                          const wxString& longHelp)
586 {
587     return new wxToolBarToolBase(this, id, label, bmpNormal, bmpDisabled, kind,
588                              clientData, shortHelp, longHelp);
589 }
590 
CreateTool(wxControl * control)591 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
592 {
593     return new wxToolBarToolBase(this, control);
594 }
595 
Create(wxWindow * parent,wxWindowID WXUNUSED (id),const wxPoint & WXUNUSED (pos),const wxSize & WXUNUSED (size),long style,const wxString & name)596 bool wxToolBar::Create(wxWindow *parent,
597                        wxWindowID WXUNUSED(id),
598                        const wxPoint& WXUNUSED(pos),
599                        const wxSize& WXUNUSED(size),
600                        long style,
601                        const wxString& name)
602 {
603     // TODO: we may need to make this a dummy hidden window to
604     // satisfy other parts of wxWidgets.
605 
606     parent->AddChild(this);
607 
608     SetWindowStyle(style);
609     SetName(name);
610 
611     return true;
612 }
613 
614 // ----------------------------------------------------------------------------
615 // adding/removing tools
616 // ----------------------------------------------------------------------------
617 
DoInsertTool(size_t WXUNUSED (pos),wxToolBarToolBase * tool)618 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
619 {
620     tool->Attach(this);
621     return true;
622 }
623 
DoDeleteTool(size_t WXUNUSED (pos),wxToolBarToolBase * tool)624 bool wxToolBar::DoDeleteTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
625 {
626     tool->Detach();
627     return true;
628 }
629 
FindToolForPosition(wxCoord WXUNUSED (x),wxCoord WXUNUSED (y)) const630 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y)) const
631 {
632     return NULL;
633 }
634 
635 // ----------------------------------------------------------------------------
636 // tool state
637 // ----------------------------------------------------------------------------
638 
DoEnableTool(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (enable))639 void wxToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(enable))
640 {
641 }
642 
DoToggleTool(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (toggle))643 void wxToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
644 {
645 }
646 
DoSetToggle(wxToolBarToolBase * WXUNUSED (tool),bool WXUNUSED (toggle))647 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
648 {
649     wxFAIL_MSG( _T("not implemented") );
650 }
651 
652 #endif
653     // !__SMARTPHONE__
654 
655 #endif // wxUSE_TOOLBAR
656