]> git.saurik.com Git - wxWidgets.git/blob - src/msw/wince/tbarwce.cpp
Fixed wxToolBar for WinCE so normal bitmaps can be used;
[wxWidgets.git] / src / msw / wince / tbarwce.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "tbarwce.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/frame.h"
33 #include "wx/log.h"
34 #include "wx/intl.h"
35 #include "wx/dynarray.h"
36 #include "wx/settings.h"
37 #include "wx/bitmap.h"
38 #include "wx/dcmemory.h"
39 #include "wx/control.h"
40 #endif
41
42 // Use the WinCE-specific toolbar only if we're either compiling
43 // with a WinCE earlier than 4, or we wish to emulate a PocketPC-style UI
44 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (_WIN32_WCE < 400 || defined(__POCKETPC__) || defined(__SMARTPHONE__))
45
46 #include "wx/toolbar.h"
47
48 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
49 #include "malloc.h"
50 #endif
51
52 #include "wx/msw/private.h"
53 #include <windows.h>
54 #include <windowsx.h>
55 #include <tchar.h>
56 #include <ole2.h>
57 #include <shellapi.h>
58 #include <commctrl.h>
59 #if defined(WINCE_WITHOUT_COMMANDBAR)
60 #include <aygshell.h>
61 #endif
62 #include "wx/msw/wince/missing.h"
63
64 #include "wx/msw/winundef.h"
65
66 #if defined(__MWERKS__) && defined(__WXMSW__)
67 // including <windef.h> for max definition doesn't seem
68 // to work using CodeWarrior 6 Windows. So we define it
69 // here. (Otherwise we get a undefined identifier 'max'
70 // later on in this file.) (Added by dimitri@shortcut.nl)
71 # ifndef max
72 # define max(a,b) (((a) > (b)) ? (a) : (b))
73 # endif
74
75 #endif
76
77 // ----------------------------------------------------------------------------
78 // constants
79 // ----------------------------------------------------------------------------
80
81 // these standard constants are not always defined in compilers headers
82
83 // Styles
84 #ifndef TBSTYLE_FLAT
85 #define TBSTYLE_LIST 0x1000
86 #define TBSTYLE_FLAT 0x0800
87 #endif
88
89 #ifndef TBSTYLE_TRANSPARENT
90 #define TBSTYLE_TRANSPARENT 0x8000
91 #endif
92
93 #ifndef TBSTYLE_TOOLTIPS
94 #define TBSTYLE_TOOLTIPS 0x0100
95 #endif
96
97 // Messages
98 #ifndef TB_GETSTYLE
99 #define TB_SETSTYLE (WM_USER + 56)
100 #define TB_GETSTYLE (WM_USER + 57)
101 #endif
102
103 #ifndef TB_HITTEST
104 #define TB_HITTEST (WM_USER + 69)
105 #endif
106
107 // these values correspond to those used by comctl32.dll
108 #define DEFAULTBITMAPX 16
109 #define DEFAULTBITMAPY 15
110 #define DEFAULTBUTTONX 24
111 #define DEFAULTBUTTONY 24
112 #define DEFAULTBARHEIGHT 27
113
114 // ----------------------------------------------------------------------------
115 // wxWin macros
116 // ----------------------------------------------------------------------------
117
118 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
119
120 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
121 EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
122 EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
123 END_EVENT_TABLE()
124
125 // ----------------------------------------------------------------------------
126 // private classes
127 // ----------------------------------------------------------------------------
128
129 class wxToolBarTool : public wxToolBarToolBase
130 {
131 public:
132 wxToolBarTool(wxToolBar *tbar,
133 int id,
134 const wxString& label,
135 const wxBitmap& bmpNormal,
136 const wxBitmap& bmpDisabled,
137 wxItemKind kind,
138 wxObject *clientData,
139 const wxString& shortHelp,
140 const wxString& longHelp)
141 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
142 clientData, shortHelp, longHelp)
143 {
144 m_nSepCount = 0;
145 m_bitmapIndex = -1;
146 }
147
148 wxToolBarTool(wxToolBar *tbar, wxControl *control)
149 : wxToolBarToolBase(tbar, control)
150 {
151 m_nSepCount = 1;
152 m_bitmapIndex = -1;
153 }
154
155 virtual void SetLabel(const wxString& label)
156 {
157 if ( label == m_label )
158 return;
159
160 wxToolBarToolBase::SetLabel(label);
161
162 // we need to update the label shown in the toolbar because it has a
163 // pointer to the internal buffer of the old label
164 //
165 // TODO: use TB_SETBUTTONINFO
166 }
167
168 // set/get the number of separators which we use to cover the space used by
169 // a control in the toolbar
170 void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
171 size_t GetSeparatorsCount() const { return m_nSepCount; }
172
173 void SetBitmapIndex(int idx) { m_bitmapIndex = idx; }
174 int GetBitmapIndex() const { return m_bitmapIndex; }
175
176 private:
177 size_t m_nSepCount;
178 int m_bitmapIndex;
179 };
180
181
182 // ============================================================================
183 // implementation
184 // ============================================================================
185
186 // ----------------------------------------------------------------------------
187 // wxToolBarTool
188 // ----------------------------------------------------------------------------
189
190 wxToolBarToolBase *wxToolBar::CreateTool(int id,
191 const wxString& label,
192 const wxBitmap& bmpNormal,
193 const wxBitmap& bmpDisabled,
194 wxItemKind kind,
195 wxObject *clientData,
196 const wxString& shortHelp,
197 const wxString& longHelp)
198 {
199 return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
200 clientData, shortHelp, longHelp);
201 }
202
203 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
204 {
205 return new wxToolBarTool(this, control);
206 }
207
208 // ----------------------------------------------------------------------------
209 // wxToolBar construction
210 // ----------------------------------------------------------------------------
211
212 void wxToolBar::Init()
213 {
214 m_nButtons = 0;
215
216 m_defaultWidth = DEFAULTBITMAPX;
217 m_defaultHeight = DEFAULTBITMAPY;
218
219 m_pInTool = 0;
220 m_menuBar = NULL;
221 }
222
223 bool wxToolBar::Create(wxWindow *parent,
224 wxWindowID id,
225 const wxPoint& pos,
226 const wxSize& size,
227 long style,
228 const wxString& name,
229 wxMenuBar* menuBar)
230 {
231 // common initialisation
232 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
233 return false;
234
235 // MSW-specific initialisation
236 if ( !MSWCreateToolbar(pos, size, menuBar) )
237 return false;
238
239 // set up the colors and fonts
240 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
241 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
242
243 return true;
244 }
245
246 #ifndef TBSTYLE_NO_DROPDOWN_ARROW
247 #define TBSTYLE_NO_DROPDOWN_ARROW 0x0080
248 #endif
249
250 bool wxToolBar::MSWCreateToolbar(const wxPoint& WXUNUSED(pos), const wxSize& WXUNUSED(size), wxMenuBar* menuBar)
251 {
252 SetMenuBar(menuBar);
253 if (m_menuBar)
254 m_menuBar->SetToolBar(this);
255
256 // Smartphone doesn't show a toolbar, it uses menu buttons.
257
258 #if !defined(__SMARTPHONE__)
259
260 #if defined(WINCE_WITHOUT_COMMANDBAR)
261 // Create the menubar.
262 SHMENUBARINFO mbi;
263
264 memset (&mbi, 0, sizeof (SHMENUBARINFO));
265 mbi.cbSize = sizeof (SHMENUBARINFO);
266 mbi.hwndParent = (HWND) GetParent()->GetHWND();
267 #ifdef __SMARTPHONE__
268 mbi.nToolBarId = 5002;
269 #else
270 mbi.nToolBarId = 5000;
271 #endif
272 mbi.nBmpId = 0;
273 mbi.cBmpImages = 0;
274 mbi.dwFlags = 0 ; // SHCMBF_EMPTYBAR;
275 mbi.hInstRes = wxGetInstance();
276
277 if (!SHCreateMenuBar(&mbi))
278 {
279 wxFAIL_MSG( _T("SHCreateMenuBar failed") );
280 return false;
281 }
282
283 SetHWND((WXHWND) mbi.hwndMB);
284 #else
285 HWND hWnd = CommandBar_Create(wxGetInstance(), (HWND) GetParent()->GetHWND(), GetId());
286 SetHWND((WXHWND) hWnd);
287 #endif
288
289 // install wxWidgets window proc for this window
290 SubclassWin(m_hWnd);
291
292 if (menuBar)
293 menuBar->Create();
294 #endif
295 // __SMARTPHONE__
296
297 return true;
298 }
299
300 void wxToolBar::Recreate()
301 {
302 #if 0
303 const HWND hwndOld = GetHwnd();
304 if ( !hwndOld )
305 {
306 // we haven't been created yet, no need to recreate
307 return;
308 }
309
310 // get the position and size before unsubclassing the old toolbar
311 const wxPoint pos = GetPosition();
312 const wxSize size = GetSize();
313
314 UnsubclassWin();
315
316 if ( !MSWCreateToolbar(pos, size) )
317 {
318 // what can we do?
319 wxFAIL_MSG( _T("recreating the toolbar failed") );
320
321 return;
322 }
323
324 // reparent all our children under the new toolbar
325 for ( wxWindowList::compatibility_iterator node = m_children.GetFirst();
326 node;
327 node = node->GetNext() )
328 {
329 wxWindow *win = node->GetData();
330 if ( !win->IsTopLevel() )
331 ::SetParent(GetHwndOf(win), GetHwnd());
332 }
333
334 // only destroy the old toolbar now -- after all the children had been
335 // reparented
336 ::DestroyWindow(hwndOld);
337
338 Realize();
339 UpdateSize();
340 #endif
341 }
342
343 wxToolBar::~wxToolBar()
344 {
345 if (GetMenuBar())
346 GetMenuBar()->SetToolBar(NULL);
347
348 // we must refresh the frame size when the toolbar is deleted but the frame
349 // is not - otherwise toolbar leaves a hole in the place it used to occupy
350 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
351 if ( frame && !frame->IsBeingDeleted() )
352 {
353 frame->SendSizeEvent();
354 }
355 }
356
357 wxSize wxToolBar::DoGetBestSize() const
358 {
359 wxSize sizeBest = GetToolSize();
360 sizeBest.x *= GetToolsCount();
361
362 // reverse horz and vertical components if necessary
363 return HasFlag(wxTB_VERTICAL) ? wxSize(sizeBest.y, sizeBest.x) : sizeBest;
364 }
365
366 // Return HMENU for the menu associated with the commandbar
367 WXHMENU wxToolBar::GetHMenu()
368 {
369 #if defined(__HANDHELDPC__)
370 // TODO ???
371 return 0;
372 #else
373 if (GetHWND())
374 {
375 return (WXHMENU) (HMENU)::SendMessage((HWND) GetHWND(), SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0);
376 }
377 else
378 return 0;
379 #endif
380 }
381
382
383 WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const
384 {
385 // toolbars never have border, giving one to them results in broken
386 // appearance
387 WXDWORD msStyle = wxControl::MSWGetStyle
388 (
389 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
390 );
391
392 // always include this one, it never hurts and setting it later only if we
393 // do have tooltips wouldn't work
394 msStyle |= TBSTYLE_TOOLTIPS;
395
396 if ( style & (wxTB_FLAT | wxTB_HORZ_LAYOUT) )
397 {
398 // static as it doesn't change during the program lifetime
399 static int s_verComCtl = wxTheApp->GetComCtl32Version();
400
401 // comctl32.dll 4.00 doesn't support the flat toolbars and using this
402 // style with 6.00 (part of Windows XP) leads to the toolbar with
403 // incorrect background colour - and not using it still results in the
404 // correct (flat) toolbar, so don't use it there
405 if ( s_verComCtl > 400 && s_verComCtl < 600 )
406 {
407 msStyle |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT;
408 }
409
410 if ( s_verComCtl >= 470 && style & wxTB_HORZ_LAYOUT )
411 {
412 msStyle |= TBSTYLE_LIST;
413 }
414 }
415
416 if ( style & wxTB_NODIVIDER )
417 msStyle |= CCS_NODIVIDER;
418
419 if ( style & wxTB_NOALIGN )
420 msStyle |= CCS_NOPARENTALIGN;
421
422 if ( style & wxTB_VERTICAL )
423 msStyle |= CCS_VERT;
424
425 return msStyle;
426 }
427
428 // ----------------------------------------------------------------------------
429 // adding/removing tools
430 // ----------------------------------------------------------------------------
431
432 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
433 {
434 // nothing special to do here - we really create the toolbar buttons in
435 // Realize() later
436 tool->Attach(this);
437
438 return true;
439 }
440
441 bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
442 {
443 // the main difficulty we have here is with the controls in the toolbars:
444 // as we (sometimes) use several separators to cover up the space used by
445 // them, the indices are not the same for us and the toolbar
446
447 // first determine the position of the first button to delete: it may be
448 // different from pos if we use several separators to cover the space used
449 // by a control
450 wxToolBarToolsList::compatibility_iterator node;
451 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
452 {
453 wxToolBarToolBase *tool2 = node->GetData();
454 if ( tool2 == tool )
455 {
456 // let node point to the next node in the list
457 node = node->GetNext();
458
459 break;
460 }
461
462 if ( tool2->IsControl() )
463 {
464 pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1;
465 }
466 }
467
468 // now determine the number of buttons to delete and the area taken by them
469 size_t nButtonsToDelete = 1;
470
471 // get the size of the button we're going to delete
472 RECT r;
473 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
474 {
475 wxLogLastError(_T("TB_GETITEMRECT"));
476 }
477
478 int width = r.right - r.left;
479
480 if ( tool->IsControl() )
481 {
482 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
483
484 width *= nButtonsToDelete;
485 }
486
487 // do delete all buttons
488 m_nButtons -= nButtonsToDelete;
489 while ( nButtonsToDelete-- > 0 )
490 {
491 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
492 {
493 wxLogLastError(wxT("TB_DELETEBUTTON"));
494
495 return false;
496 }
497 }
498
499 tool->Detach();
500
501 // and finally reposition all the controls after this button (the toolbar
502 // takes care of all normal items)
503 for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
504 {
505 wxToolBarToolBase *tool2 = node->GetData();
506 if ( tool2->IsControl() )
507 {
508 int x;
509 wxControl *control = tool2->GetControl();
510 control->GetPosition(&x, NULL);
511 control->Move(x - width, wxDefaultCoord);
512 }
513 }
514
515 return true;
516 }
517
518 bool wxToolBar::Realize()
519 {
520 #if defined(__SMARTPHONE__)
521 return true;
522 #else
523 const size_t nTools = GetToolsCount();
524 if ( nTools == 0 )
525 {
526 // nothing to do
527 return true;
528 }
529
530 #if 0
531 // delete all old buttons, if any
532 for ( size_t pos = 0; pos < m_nButtons; pos++ )
533 {
534 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
535 {
536 wxLogDebug(wxT("TB_DELETEBUTTON failed"));
537 }
538 }
539 #endif // 0
540
541 bool lastWasRadio = false;
542 wxToolBarToolsList::Node* node;
543 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
544 {
545 wxToolBarTool *tool = (wxToolBarTool*) node->GetData();
546
547 TBBUTTON buttons[1] ;
548
549 TBBUTTON& button = buttons[0];
550
551 wxZeroMemory(button);
552
553 bool isRadio = false;
554 switch ( tool->GetStyle() )
555 {
556 case wxTOOL_STYLE_CONTROL:
557 button.idCommand = tool->GetId();
558 // fall through: create just a separator too
559
560 case wxTOOL_STYLE_SEPARATOR:
561 button.fsState = TBSTATE_ENABLED;
562 button.fsStyle = TBSTYLE_SEP;
563 break;
564
565 case wxTOOL_STYLE_BUTTON:
566
567 if ( HasFlag(wxTB_TEXT) )
568 {
569 const wxString& label = tool->GetLabel();
570 if ( !label.empty() )
571 {
572 button.iString = (int)label.c_str();
573 }
574 }
575
576 const wxBitmap& bmp = tool->GetNormalBitmap();
577
578 wxBitmap bmpToUse = bmp;
579
580 if (bmp.GetWidth() < 16 || bmp.GetHeight() < 16)
581 {
582 wxMemoryDC memDC;
583 wxBitmap b(16,16);
584 memDC.SelectObject(b);
585 memDC.SetBackground(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
586 memDC.Clear();
587 int x = (16 - bmp.GetWidth())/2;
588 int y = (16 - bmp.GetHeight())/2;
589 memDC.DrawBitmap(bmp, x, y, true);
590 memDC.SelectObject(wxNullBitmap);
591
592 bmpToUse = b;
593 tool->SetNormalBitmap(b);
594 }
595
596 int n = 0;
597 if ( bmpToUse.Ok() )
598 {
599 n = ::CommandBar_AddBitmap( (HWND) GetHWND(), NULL, (int) (HBITMAP) bmpToUse.GetHBITMAP(),
600 1, 16, 16 );
601 }
602
603 button.idCommand = tool->GetId();
604 button.iBitmap = n;
605
606 if ( tool->IsEnabled() )
607 button.fsState |= TBSTATE_ENABLED;
608 if ( tool->IsToggled() )
609 button.fsState |= TBSTATE_CHECKED;
610
611 switch ( tool->GetKind() )
612 {
613 case wxITEM_RADIO:
614 button.fsStyle = TBSTYLE_CHECKGROUP;
615
616 if ( !lastWasRadio )
617 {
618 // the first item in the radio group is checked by
619 // default to be consistent with wxGTK and the menu
620 // radio items
621 button.fsState |= TBSTATE_CHECKED;
622
623 tool->Toggle(true);
624 }
625
626 isRadio = true;
627 break;
628
629 case wxITEM_CHECK:
630 button.fsStyle = TBSTYLE_CHECK;
631 break;
632
633 default:
634 wxFAIL_MSG( _T("unexpected toolbar button kind") );
635 // fall through
636
637 case wxITEM_NORMAL:
638 button.fsStyle = TBSTYLE_BUTTON;
639 }
640 break;
641 }
642
643 BOOL bRc = ::CommandBar_AddButtons( (HWND) GetHWND(), 1, buttons );
644
645 wxASSERT_MSG( bRc, wxT("Could not add toolbar button."));
646
647 lastWasRadio = isRadio;
648 }
649
650 return true;
651 #endif
652 // __SMARTPHONE__
653 }
654
655 // ----------------------------------------------------------------------------
656 // message handlers
657 // ----------------------------------------------------------------------------
658
659 bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
660 {
661 wxToolBarToolBase *tool = FindById((int)id);
662 if ( !tool )
663 {
664 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
665 event.SetEventObject(this);
666 event.SetId(id);
667 event.SetInt(id);
668
669 return GetEventHandler()->ProcessEvent(event);
670 }
671
672 if ( tool->CanBeToggled() )
673 {
674 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
675 tool->Toggle((state & TBSTATE_CHECKED) != 0);
676 }
677
678 bool toggled = tool->IsToggled();
679
680 // avoid sending the event when a radio button is released, this is not
681 // interesting
682 if ( !tool->CanBeToggled() || tool->GetKind() != wxITEM_RADIO || toggled )
683 {
684 // OnLeftClick() can veto the button state change - for buttons which
685 // may be toggled only, of couse
686 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
687 {
688 // revert back
689 toggled = !toggled;
690 tool->SetToggle(toggled);
691
692 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
693 }
694 }
695
696 return true;
697 }
698
699 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
700 WXLPARAM lParam,
701 WXLPARAM *WXUNUSED(result))
702 {
703 #if wxUSE_TOOLTIPS
704 // First check if this applies to us
705 NMHDR *hdr = (NMHDR *)lParam;
706
707 // the tooltips control created by the toolbar is sometimes Unicode, even
708 // in an ANSI application - this seems to be a bug in comctl32.dll v5
709 UINT code = hdr->code;
710 if ( (code != (UINT) TTN_NEEDTEXTA) && (code != (UINT) TTN_NEEDTEXTW) )
711 return false;
712
713 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
714 if ( toolTipWnd != hdr->hwndFrom )
715 return false;
716
717 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
718 int id = (int)ttText->hdr.idFrom;
719
720 wxToolBarToolBase *tool = FindById(id);
721 if ( !tool )
722 return false;
723
724 return HandleTooltipNotify(code, lParam, tool->GetShortHelp());
725 #else
726 wxUnusedVar(lParam);
727 return false;
728 #endif
729 }
730
731 // ----------------------------------------------------------------------------
732 // toolbar geometry
733 // ----------------------------------------------------------------------------
734
735 void wxToolBar::SetToolBitmapSize(const wxSize& size)
736 {
737 wxToolBarBase::SetToolBitmapSize(size);
738
739 ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
740 }
741
742 void wxToolBar::SetRows(int nRows)
743 {
744 if ( nRows == m_maxRows )
745 {
746 // avoid resizing the frame uselessly
747 return;
748 }
749
750 // TRUE in wParam means to create at least as many rows, FALSE -
751 // at most as many
752 RECT rect;
753 ::SendMessage(GetHwnd(), TB_SETROWS,
754 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
755 (LPARAM) &rect);
756
757 m_maxRows = nRows;
758
759 UpdateSize();
760 }
761
762 // The button size is bigger than the bitmap size
763 wxSize wxToolBar::GetToolSize() const
764 {
765 // TB_GETBUTTONSIZE is supported from version 4.70
766 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \
767 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
768 if ( wxTheApp->GetComCtl32Version() >= 470 )
769 {
770 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
771
772 return wxSize(LOWORD(dw), HIWORD(dw));
773 }
774 else
775 #endif // comctl32.dll 4.70+
776 {
777 // defaults
778 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
779 }
780 }
781
782 static
783 wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
784 size_t index )
785 {
786 wxToolBarToolsList::compatibility_iterator current = tools.GetFirst();
787
788 for ( ; current != 0; current = current->GetNext() )
789 {
790 if ( index == 0 )
791 return current->GetData();
792
793 wxToolBarTool *tool = (wxToolBarTool *)current->GetData();
794 size_t separators = tool->GetSeparatorsCount();
795
796 // if it is a normal button, sepcount == 0, so skip 1 item (the button)
797 // otherwise, skip as many items as the separator count, plus the
798 // control itself
799 index -= separators ? separators + 1 : 1;
800 }
801
802 return 0;
803 }
804
805 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
806 {
807 POINT pt;
808 pt.x = x;
809 pt.y = y;
810 int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
811 // MBN: when the point ( x, y ) is close to the toolbar border
812 // TB_HITTEST returns m_nButtons ( not -1 )
813 if ( index < 0 || (size_t)index >= m_nButtons )
814 {
815 // it's a separator or there is no tool at all there
816 return (wxToolBarToolBase *)NULL;
817 }
818
819 // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers
820 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
821 if ( wxTheApp->GetComCtl32Version() >= 471 )
822 {
823 return m_tools.Item((size_t)index)->GetData();
824 }
825 else
826 #endif
827 {
828 return GetItemSkippingDummySpacers( m_tools, (size_t) index );
829 }
830 }
831
832 void wxToolBar::UpdateSize()
833 {
834 // the toolbar size changed
835 ::SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0);
836
837 // we must also refresh the frame after the toolbar size (possibly) changed
838 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
839 if ( frame )
840 {
841 frame->SendSizeEvent();
842 }
843 }
844
845 // ----------------------------------------------------------------------------
846 // toolbar styles
847 // ---------------------------------------------------------------------------
848
849 void wxToolBar::SetWindowStyleFlag(long style)
850 {
851 // the style bits whose changes force us to recreate the toolbar
852 static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS;
853
854 const long styleOld = GetWindowStyle();
855
856 wxToolBarBase::SetWindowStyleFlag(style);
857
858 // don't recreate an empty toolbar: not only this is unnecessary, but it is
859 // also fatal as we'd then try to recreate the toolbar when it's just being
860 // created
861 if ( GetToolsCount() &&
862 (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
863 {
864 // to remove the text labels, simply re-realizing the toolbar is enough
865 // but I don't know of any way to add the text to an existing toolbar
866 // other than by recreating it entirely
867 Recreate();
868 }
869 }
870
871 // ----------------------------------------------------------------------------
872 // tool state
873 // ----------------------------------------------------------------------------
874
875 void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
876 {
877 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
878 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
879 }
880
881 void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
882 {
883 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
884 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
885 }
886
887 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
888 {
889 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
890 // without, so we really need to delete the button and recreate it here
891 wxFAIL_MSG( _T("not implemented") );
892 }
893
894 // ----------------------------------------------------------------------------
895 // event handlers
896 // ----------------------------------------------------------------------------
897
898 // Responds to colour changes, and passes event on to children.
899 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
900 {
901 wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));
902
903 // Remap the buttons
904 Realize();
905
906 // Relayout the toolbar
907 int nrows = m_maxRows;
908 m_maxRows = 0; // otherwise SetRows() wouldn't do anything
909 SetRows(nrows);
910
911 Refresh();
912
913 // let the event propagate further
914 event.Skip();
915 }
916
917 void wxToolBar::OnMouseEvent(wxMouseEvent& event)
918 {
919 if (event.Leaving() && m_pInTool)
920 {
921 OnMouseEnter( -1 );
922 event.Skip();
923 return;
924 }
925
926 if (event.RightDown())
927 {
928 // For now, we don't have an id. Later we could
929 // try finding the tool.
930 OnRightClick((int)-1, event.GetX(), event.GetY());
931 }
932 else
933 {
934 event.Skip();
935 }
936 }
937
938 void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
939 {
940 wxCoord x = GET_X_LPARAM(lParam),
941 y = GET_Y_LPARAM(lParam);
942 wxToolBarToolBase* tool = FindToolForPosition( x, y );
943
944 // cursor left current tool
945 if( tool != m_pInTool && !tool )
946 {
947 m_pInTool = 0;
948 OnMouseEnter( -1 );
949 }
950
951 // cursor entered a tool
952 if( tool != m_pInTool && tool )
953 {
954 m_pInTool = tool;
955 OnMouseEnter( tool->GetId() );
956 }
957 }
958
959 WXLRESULT wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
960 {
961 #if 0
962 switch ( nMsg )
963 {
964 case WM_SIZE:
965 if ( HandleSize(wParam, lParam) )
966 return 0;
967 break;
968
969 case WM_MOUSEMOVE:
970 // we don't handle mouse moves, so always pass the message to
971 // wxControl::MSWWindowProc
972 HandleMouseMove(wParam, lParam);
973 break;
974 }
975 #endif
976 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
977 }
978
979 #endif // wxUSE_TOOLBAR && Win95
980