]> git.saurik.com Git - wxWidgets.git/blame - src/msw/wince/tbarwce.cpp
fixes for win32
[wxWidgets.git] / src / msw / wince / tbarwce.cpp
CommitLineData
39d2f9a7
JS
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#ifdef __GNUG__
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#if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE
43
44#include "wx/toolbar.h"
45
46#if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
47 #include "malloc.h"
48#endif
49
50#include "wx/msw/private.h"
51#include <windows.h>
52#include <windowsx.h>
53#include <tchar.h>
54#include <ole2.h>
55#include <commctrl.h>
56#include <aygshell.h>
57
58#include "wx/msw/winundef.h"
59
60#if defined(__MWERKS__) && defined(__WXMSW__)
61// including <windef.h> for max definition doesn't seem
62// to work using CodeWarrior 6 Windows. So we define it
63// here. (Otherwise we get a undefined identifier 'max'
64// later on in this file.) (Added by dimitri@shortcut.nl)
65# ifndef max
66# define max(a,b) (((a) > (b)) ? (a) : (b))
67# endif
68
69#endif
70
71// ----------------------------------------------------------------------------
72// conditional compilation
73// ----------------------------------------------------------------------------
74
75// wxWindows previously always considered that toolbar buttons have light grey
76// (0xc0c0c0) background and so ignored any bitmap masks - however, this
77// doesn't work with XPMs which then appear to have black background. To make
78// this work, we must respect the bitmap masks - which we do now. This should
79// be ok in any case, but to restore 100% compatible with the old version
80// behaviour, you can set this to 0.
81#define USE_BITMAP_MASKS 1
82
83// ----------------------------------------------------------------------------
84// constants
85// ----------------------------------------------------------------------------
86
87// these standard constants are not always defined in compilers headers
88
89// Styles
90#ifndef TBSTYLE_FLAT
91 #define TBSTYLE_LIST 0x1000
92 #define TBSTYLE_FLAT 0x0800
93#endif
94
95#ifndef TBSTYLE_TRANSPARENT
96 #define TBSTYLE_TRANSPARENT 0x8000
97#endif
98
99#ifndef TBSTYLE_TOOLTIPS
100 #define TBSTYLE_TOOLTIPS 0x0100
101#endif
102
103// Messages
104#ifndef TB_GETSTYLE
105 #define TB_SETSTYLE (WM_USER + 56)
106 #define TB_GETSTYLE (WM_USER + 57)
107#endif
108
109#ifndef TB_HITTEST
110 #define TB_HITTEST (WM_USER + 69)
111#endif
112
113// these values correspond to those used by comctl32.dll
114#define DEFAULTBITMAPX 16
115#define DEFAULTBITMAPY 15
116#define DEFAULTBUTTONX 24
117#define DEFAULTBUTTONY 24
118#define DEFAULTBARHEIGHT 27
119
120// ----------------------------------------------------------------------------
121// wxWin macros
122// ----------------------------------------------------------------------------
123
124IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
125
126BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
127 EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
128 EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
129END_EVENT_TABLE()
130
131// ----------------------------------------------------------------------------
132// private classes
133// ----------------------------------------------------------------------------
134
135class wxToolBarTool : public wxToolBarToolBase
136{
137public:
138 wxToolBarTool(wxToolBar *tbar,
139 int id,
140 const wxString& label,
141 const wxBitmap& bmpNormal,
142 const wxBitmap& bmpDisabled,
143 wxItemKind kind,
144 wxObject *clientData,
145 const wxString& shortHelp,
146 const wxString& longHelp)
147 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
148 clientData, shortHelp, longHelp)
149 {
150 m_nSepCount = 0;
151 }
152
153 wxToolBarTool(wxToolBar *tbar, wxControl *control)
154 : wxToolBarToolBase(tbar, control)
155 {
156 m_nSepCount = 1;
157 }
158
159 virtual void SetLabel(const wxString& label)
160 {
161 if ( label == m_label )
162 return;
163
164 wxToolBarToolBase::SetLabel(label);
165
166 // we need to update the label shown in the toolbar because it has a
167 // pointer to the internal buffer of the old label
168 //
169 // TODO: use TB_SETBUTTONINFO
170 }
171
172 // set/get the number of separators which we use to cover the space used by
173 // a control in the toolbar
174 void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
175 size_t GetSeparatorsCount() const { return m_nSepCount; }
176
177private:
178 size_t m_nSepCount;
179};
180
181
182// ============================================================================
183// implementation
184// ============================================================================
185
186// ----------------------------------------------------------------------------
187// wxToolBarTool
188// ----------------------------------------------------------------------------
189
190wxToolBarToolBase *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
203wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
204{
205 return new wxToolBarTool(this, control);
206}
207
208// ----------------------------------------------------------------------------
209// wxToolBar construction
210// ----------------------------------------------------------------------------
211
212void wxToolBar::Init()
213{
214 m_hBitmap = 0;
215
216 m_nButtons = 0;
217
218 m_defaultWidth = DEFAULTBITMAPX;
219 m_defaultHeight = DEFAULTBITMAPY;
220
221 m_pInTool = 0;
222 m_menuBar = NULL;
223}
224
225bool wxToolBar::Create(wxWindow *parent,
226 wxWindowID id,
227 const wxPoint& pos,
228 const wxSize& size,
229 long style,
230 const wxString& name,
231 wxMenuBar* menuBar)
232{
233 // common initialisation
234 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
235 return FALSE;
236
237 // MSW-specific initialisation
238 if ( !MSWCreateToolbar(pos, size, menuBar) )
239 return FALSE;
240
241 // set up the colors and fonts
242 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
243 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
244
245 return TRUE;
246}
247
248#ifndef TBSTYLE_NO_DROPDOWN_ARROW
249#define TBSTYLE_NO_DROPDOWN_ARROW 0x0080
250#endif
251
252bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size, wxMenuBar* menuBar)
253{
254 SetMenuBar(menuBar);
255 if (m_menuBar)
256 m_menuBar->SetToolBar(this);
257
258 // Create the menubar.
259 SHMENUBARINFO mbi;
260
261 memset (&mbi, 0, sizeof (SHMENUBARINFO));
262 mbi.cbSize = sizeof (SHMENUBARINFO);
263 mbi.hwndParent = (HWND) GetParent()->GetHWND();
264 mbi.nToolBarId = 5000;
265 mbi.nBmpId = 0;
266 mbi.cBmpImages = 0;
267 mbi.dwFlags = 0 ; // SHCMBF_EMPTYBAR;
268 mbi.hInstRes = wxGetInstance();
269
270 if (!SHCreateMenuBar(&mbi))
271 {
272 wxFAIL_MSG( _T("SHCreateMenuBar failed") );
273 return FALSE;
274 }
275
276 SetHWND((WXHWND) mbi.hwndMB);
277/*
278 if (!::SendMessage((HWND) GetHWND(), TB_DELETEBUTTON, 0, (LPARAM) 0))
279 {
280 wxLogLastError(wxT("TB_DELETEBUTTON"));
281 }
282*/
283 // install wxWindows window proc for this window
284 SubclassWin(m_hWnd);
285
286 if (menuBar)
287 menuBar->Create();
39d2f9a7 288
39d2f9a7
JS
289 return TRUE;
290}
291
292void wxToolBar::Recreate()
293{
294#if 0
295 const HWND hwndOld = GetHwnd();
296 if ( !hwndOld )
297 {
298 // we haven't been created yet, no need to recreate
299 return;
300 }
301
302 // get the position and size before unsubclassing the old toolbar
303 const wxPoint pos = GetPosition();
304 const wxSize size = GetSize();
305
306 UnsubclassWin();
307
308 if ( !MSWCreateToolbar(pos, size) )
309 {
310 // what can we do?
311 wxFAIL_MSG( _T("recreating the toolbar failed") );
312
313 return;
314 }
315
316 // reparent all our children under the new toolbar
317 for ( wxWindowList::compatibility_iterator node = m_children.GetFirst();
318 node;
319 node = node->GetNext() )
320 {
321 wxWindow *win = node->GetData();
322 if ( !win->IsTopLevel() )
323 ::SetParent(GetHwndOf(win), GetHwnd());
324 }
325
326 // only destroy the old toolbar now -- after all the children had been
327 // reparented
328 ::DestroyWindow(hwndOld);
329
330 // it is for the old bitmap control and can't be used with the new one
331 if ( m_hBitmap )
332 {
333 ::DeleteObject((HBITMAP) m_hBitmap);
334 m_hBitmap = 0;
335 }
336
337 Realize();
338 UpdateSize();
339#endif
340}
341
342wxToolBar::~wxToolBar()
343{
bf95a04f
JS
344 if (GetMenuBar())
345 GetMenuBar()->SetToolBar(NULL);
346
39d2f9a7
JS
347 // we must refresh the frame size when the toolbar is deleted but the frame
348 // is not - otherwise toolbar leaves a hole in the place it used to occupy
349 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
350 if ( frame && !frame->IsBeingDeleted() )
351 {
352 frame->SendSizeEvent();
353 }
354
355 if ( m_hBitmap )
356 {
357 ::DeleteObject((HBITMAP) m_hBitmap);
358 }
359}
360
361wxSize wxToolBar::DoGetBestSize() const
362{
363 wxSize sizeBest = GetToolSize();
364 sizeBest.x *= GetToolsCount();
365
366 // reverse horz and vertical components if necessary
367 return HasFlag(wxTB_VERTICAL) ? wxSize(sizeBest.y, sizeBest.x) : sizeBest;
368}
369
370// Return HMENU for the menu associated with the commandbar
371WXHMENU wxToolBar::GetHMenu()
372{
373 if (GetHWND())
374 {
375 return (WXHMENU) (HMENU)::SendMessage((HWND) GetHWND(), SHCMBM_GETMENU, (WPARAM)0, (LPARAM)0);
376 }
377 else
378 return 0;
379}
380
381
382WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const
383{
384 // toolbars never have border, giving one to them results in broken
385 // appearance
386 WXDWORD msStyle = wxControl::MSWGetStyle
387 (
388 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
389 );
390
391 // always include this one, it never hurts and setting it later only if we
392 // do have tooltips wouldn't work
393 msStyle |= TBSTYLE_TOOLTIPS;
394
395 if ( style & (wxTB_FLAT | wxTB_HORZ_LAYOUT) )
396 {
397 // static as it doesn't change during the program lifetime
398 static int s_verComCtl = wxTheApp->GetComCtl32Version();
399
400 // comctl32.dll 4.00 doesn't support the flat toolbars and using this
401 // style with 6.00 (part of Windows XP) leads to the toolbar with
402 // incorrect background colour - and not using it still results in the
403 // correct (flat) toolbar, so don't use it there
404 if ( s_verComCtl > 400 && s_verComCtl < 600 )
405 {
406 msStyle |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT;
407 }
408
409 if ( s_verComCtl >= 470 && style & wxTB_HORZ_LAYOUT )
410 {
411 msStyle |= TBSTYLE_LIST;
412 }
413 }
414
415 if ( style & wxTB_NODIVIDER )
416 msStyle |= CCS_NODIVIDER;
417
418 if ( style & wxTB_NOALIGN )
419 msStyle |= CCS_NOPARENTALIGN;
420
421 if ( style & wxTB_VERTICAL )
422 msStyle |= CCS_VERT;
423
424 return msStyle;
425}
426
427// ----------------------------------------------------------------------------
428// adding/removing tools
429// ----------------------------------------------------------------------------
430
431bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
432{
433 // nothing special to do here - we really create the toolbar buttons in
434 // Realize() later
435 tool->Attach(this);
436
437 return TRUE;
438}
439
440bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
441{
442 // the main difficulty we have here is with the controls in the toolbars:
443 // as we (sometimes) use several separators to cover up the space used by
444 // them, the indices are not the same for us and the toolbar
445
446 // first determine the position of the first button to delete: it may be
447 // different from pos if we use several separators to cover the space used
448 // by a control
449 wxToolBarToolsList::compatibility_iterator node;
450 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
451 {
452 wxToolBarToolBase *tool2 = node->GetData();
453 if ( tool2 == tool )
454 {
455 // let node point to the next node in the list
456 node = node->GetNext();
457
458 break;
459 }
460
461 if ( tool2->IsControl() )
462 {
463 pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1;
464 }
465 }
466
467 // now determine the number of buttons to delete and the area taken by them
468 size_t nButtonsToDelete = 1;
469
470 // get the size of the button we're going to delete
471 RECT r;
472 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
473 {
474 wxLogLastError(_T("TB_GETITEMRECT"));
475 }
476
477 int width = r.right - r.left;
478
479 if ( tool->IsControl() )
480 {
481 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
482
483 width *= nButtonsToDelete;
484 }
485
486 // do delete all buttons
487 m_nButtons -= nButtonsToDelete;
488 while ( nButtonsToDelete-- > 0 )
489 {
490 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
491 {
492 wxLogLastError(wxT("TB_DELETEBUTTON"));
493
494 return FALSE;
495 }
496 }
497
498 tool->Detach();
499
500 // and finally reposition all the controls after this button (the toolbar
501 // takes care of all normal items)
502 for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
503 {
504 wxToolBarToolBase *tool2 = node->GetData();
505 if ( tool2->IsControl() )
506 {
507 int x;
508 wxControl *control = tool2->GetControl();
509 control->GetPosition(&x, NULL);
510 control->Move(x - width, -1);
511 }
512 }
513
514 return TRUE;
515}
516
bf95a04f
JS
517struct wxToolBarIdMapping
518{
519 int m_wxwinId;
520 int m_winceId;
521};
522
523static wxToolBarIdMapping sm_ToolBarIdMappingArray[] =
524{
525 { wxID_COPY, STD_COPY },
526 { wxID_CUT, STD_CUT },
527 { wxID_FIND, STD_FIND },
528 { wxID_PASTE, STD_PASTE },
529 { wxID_NEW, STD_FILENEW },
530 { wxID_OPEN, STD_FILEOPEN },
531 { wxID_SAVE, STD_FILESAVE },
532 { wxID_PRINT, STD_PRINT },
533 { wxID_PREVIEW, STD_PRINTPRE },
534 { wxID_UNDO, STD_UNDO },
535 { wxID_REDO, STD_REDOW },
536 { wxID_HELP, STD_HELP },
537 { wxID_DELETE, STD_DELETE },
538 { wxID_REPLACE, STD_REPLACE },
539 { wxID_PROPERTIES, STD_PROPERTIES },
540 { wxID_VIEW_DETAILS, VIEW_DETAILS },
541 { wxID_VIEW_SORTDATE, VIEW_SORTDATE },
542 { wxID_VIEW_LARGEICONS, VIEW_LARGEICONS },
543 { wxID_VIEW_SORTNAME, VIEW_SORTNAME },
544 { wxID_VIEW_LIST, VIEW_LIST },
545 { wxID_VIEW_SORTSIZE, VIEW_SORTSIZE },
546 { wxID_VIEW_SMALLICONS, VIEW_SMALLICONS },
547 { wxID_VIEW_SORTTYPE, VIEW_SORTTYPE },
548 { 0, 0},
549};
550
551static int wxFindIdForWinceId(int id)
552{
553 int i = 0;
554 while (TRUE)
555 {
556 if (sm_ToolBarIdMappingArray[i].m_winceId == 0)
557 return -1;
558 else if (sm_ToolBarIdMappingArray[i].m_winceId == id)
559 return sm_ToolBarIdMappingArray[i].m_wxwinId;
560 i ++;
561 }
562 return -1;
563}
564
565static int wxFindIdForwxWinId(int id)
566{
567 int i = 0;
568 while (TRUE)
569 {
570 if (sm_ToolBarIdMappingArray[i].m_wxwinId == 0)
571 return -1;
572 else if (sm_ToolBarIdMappingArray[i].m_wxwinId == id)
573 return sm_ToolBarIdMappingArray[i].m_winceId;
574 i ++;
575 }
576 return -1;
577}
578
579
39d2f9a7
JS
580bool wxToolBar::Realize()
581{
582 const size_t nTools = GetToolsCount();
583 if ( nTools == 0 )
584 {
585 // nothing to do
586 return TRUE;
587 }
588
589 const bool isVertical = HasFlag(wxTB_VERTICAL);
590
591#if 0
592 // delete all old buttons, if any
593 for ( size_t pos = 0; pos < m_nButtons; pos++ )
594 {
595 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
596 {
597 wxLogDebug(wxT("TB_DELETEBUTTON failed"));
598 }
599 }
600#endif
601
602 // add the buttons and separators
603 // ------------------------------
604
bf95a04f
JS
605 // Use standard buttons
606 CommandBar_AddBitmap((HWND) GetHWND(), HINST_COMMCTRL,
607 IDB_STD_SMALL_COLOR, 0, 16, 16);
608
39d2f9a7
JS
609 TBBUTTON *buttons = new TBBUTTON[nTools];
610
611 // this array will hold the indices of all controls in the toolbar
612 wxArrayInt controlIds;
613
614 bool lastWasRadio = FALSE;
615 int i = 0;
616 wxToolBarToolsList::Node* node;
617 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
618 {
619 wxToolBarToolBase *tool = node->GetData();
620
bf95a04f
JS
621 bool processedThis = TRUE;
622
39d2f9a7
JS
623 TBBUTTON& button = buttons[i];
624
625 wxZeroMemory(button);
626
627 bool isRadio = FALSE;
628 switch ( tool->GetStyle() )
629 {
630 case wxTOOL_STYLE_CONTROL:
631 button.idCommand = tool->GetId();
632 // fall through: create just a separator too
633
634 case wxTOOL_STYLE_SEPARATOR:
635 button.fsState = TBSTATE_ENABLED;
636 button.fsStyle = TBSTYLE_SEP;
637 break;
638
639 case wxTOOL_STYLE_BUTTON:
bf95a04f
JS
640// if ( !HasFlag(wxTB_NOICONS) )
641// button.iBitmap = bitmapId;
39d2f9a7
JS
642
643 if ( HasFlag(wxTB_TEXT) )
644 {
645 const wxString& label = tool->GetLabel();
646 if ( !label.empty() )
647 {
648 button.iString = (int)label.c_str();
649 }
650 }
651
bf95a04f
JS
652 int winceId = wxFindIdForwxWinId(tool->GetId());
653 if (winceId > -1)
654 {
655 button.idCommand = tool->GetId();
656// if ( !HasFlag(wxTB_NOICONS) )
657 button.iBitmap = winceId;
658 }
659 else
660 processedThis = FALSE;
39d2f9a7
JS
661
662 if ( tool->IsEnabled() )
663 button.fsState |= TBSTATE_ENABLED;
664 if ( tool->IsToggled() )
665 button.fsState |= TBSTATE_CHECKED;
666
667 switch ( tool->GetKind() )
668 {
669 case wxITEM_RADIO:
670 button.fsStyle = TBSTYLE_CHECKGROUP;
671
672 if ( !lastWasRadio )
673 {
674 // the first item in the radio group is checked by
675 // default to be consistent with wxGTK and the menu
676 // radio items
677 button.fsState |= TBSTATE_CHECKED;
678
679 tool->Toggle(TRUE);
680 }
681
682 isRadio = TRUE;
683 break;
684
685 case wxITEM_CHECK:
686 button.fsStyle = TBSTYLE_CHECK;
687 break;
688
689 default:
690 wxFAIL_MSG( _T("unexpected toolbar button kind") );
691 // fall through
692
693 case wxITEM_NORMAL:
694 button.fsStyle = TBSTYLE_BUTTON;
695 }
696
bf95a04f 697// bitmapId++;
39d2f9a7
JS
698 break;
699 }
700
701 lastWasRadio = isRadio;
702
bf95a04f
JS
703 if (processedThis)
704 i++;
39d2f9a7
JS
705 }
706
bf95a04f 707 // Add buttons to Commandbar
39d2f9a7
JS
708 if (!CommandBar_AddButtons(GetHwnd(), i, buttons))
709 {
710 wxLogLastError(wxT("CommandBar_AddButtons"));
711 }
712
713 delete [] buttons;
714
715#if 0
716 // Deal with the controls finally
717 // ------------------------------
718
719 // adjust the controls size to fit nicely in the toolbar
720 int y = 0;
721 size_t index = 0;
722 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
723 {
724 wxToolBarToolBase *tool = node->GetData();
725
726 // we calculate the running y coord for vertical toolbars so we need to
727 // get the items size for all items but for the horizontal ones we
728 // don't need to deal with the non controls
729 bool isControl = tool->IsControl();
730 if ( !isControl && !isVertical )
731 continue;
732
733 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
734 // latter only appeared in v4.70 of comctl32.dll
735 RECT r;
736 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
737 index, (LPARAM)(LPRECT)&r) )
738 {
739 wxLogLastError(wxT("TB_GETITEMRECT"));
740 }
741
742 if ( !isControl )
743 {
744 // can only be control if isVertical
745 y += r.bottom - r.top;
746
747 continue;
748 }
749
750 wxControl *control = tool->GetControl();
751
752 wxSize size = control->GetSize();
753
754 // the position of the leftmost controls corner
755 int left = -1;
756
757 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
758#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
759 // available in headers, now check whether it is available now
760 // (during run-time)
761 if ( wxTheApp->GetComCtl32Version() >= 471 )
762 {
763 // set the (underlying) separators width to be that of the
764 // control
765 TBBUTTONINFO tbbi;
766 tbbi.cbSize = sizeof(tbbi);
767 tbbi.dwMask = TBIF_SIZE;
768 tbbi.cx = size.x;
769 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
770 tool->GetId(), (LPARAM)&tbbi) )
771 {
772 // the id is probably invalid?
773 wxLogLastError(wxT("TB_SETBUTTONINFO"));
774 }
775 }
776 else
777#endif // comctl32.dll 4.71
778 // TB_SETBUTTONINFO unavailable
779 {
780 // try adding several separators to fit the controls width
781 int widthSep = r.right - r.left;
782 left = r.left;
783
784 TBBUTTON tbb;
785 wxZeroMemory(tbb);
786 tbb.idCommand = 0;
787 tbb.fsState = TBSTATE_ENABLED;
788 tbb.fsStyle = TBSTYLE_SEP;
789
790 size_t nSeparators = size.x / widthSep;
791 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
792 {
793 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
794 index, (LPARAM)&tbb) )
795 {
796 wxLogLastError(wxT("TB_INSERTBUTTON"));
797 }
798
799 index++;
800 }
801
802 // remember the number of separators we used - we'd have to
803 // delete all of them later
804 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
805
806 // adjust the controls width to exactly cover the separators
807 control->SetSize((nSeparators + 1)*widthSep, -1);
808 }
809
810 // position the control itself correctly vertically
811 int height = r.bottom - r.top;
812 int diff = height - size.y;
813 if ( diff < 0 )
814 {
815 // the control is too high, resize to fit
816 control->SetSize(-1, height - 2);
817
818 diff = 2;
819 }
820
821 int top;
822 if ( isVertical )
823 {
824 left = 0;
825 top = y;
826
827 y += height + 2*GetMargins().y;
828 }
829 else // horizontal toolbar
830 {
831 if ( left == -1 )
832 left = r.left;
833
834 top = r.top;
835 }
836
837 control->Move(left, top + (diff + 1) / 2);
838 }
839
840 // the max index is the "real" number of buttons - i.e. counting even the
841 // separators which we added just for aligning the controls
842 m_nButtons = index;
843
844 if ( !isVertical )
845 {
846 if ( m_maxRows == 0 )
847 {
848 // if not set yet, only one row
849 SetRows(1);
850 }
851 }
852 else if ( m_nButtons > 0 ) // vertical non empty toolbar
853 {
854 if ( m_maxRows == 0 )
855 {
856 // if not set yet, have one column
857 SetRows(m_nButtons);
858 }
859 }
860#endif
861
862 return TRUE;
863}
864
865// ----------------------------------------------------------------------------
866// message handlers
867// ----------------------------------------------------------------------------
868
869bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
870{
871 wxToolBarToolBase *tool = FindById((int)id);
872 if ( !tool )
873 {
874 wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED);
875 event.SetEventObject(this);
876 event.SetId(id);
877 event.SetInt(id);
878
879 return GetEventHandler()->ProcessEvent(event);
880 }
881
882 if ( tool->CanBeToggled() )
883 {
884 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
885 tool->Toggle((state & TBSTATE_CHECKED) != 0);
886 }
887
888 bool toggled = tool->IsToggled();
889
890 // avoid sending the event when a radio button is released, this is not
891 // interesting
892 if ( !tool->CanBeToggled() || tool->GetKind() != wxITEM_RADIO || toggled )
893 {
894 // OnLeftClick() can veto the button state change - for buttons which
895 // may be toggled only, of couse
896 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
897 {
898 // revert back
899 toggled = !toggled;
900 tool->SetToggle(toggled);
901
902 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
903 }
904 }
905
906 return TRUE;
907}
908
909bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
910 WXLPARAM lParam,
911 WXLPARAM *WXUNUSED(result))
912{
913#if wxUSE_TOOLTIPS
914 // First check if this applies to us
915 NMHDR *hdr = (NMHDR *)lParam;
916
917 // the tooltips control created by the toolbar is sometimes Unicode, even
918 // in an ANSI application - this seems to be a bug in comctl32.dll v5
919 UINT code = hdr->code;
920 if ( (code != (UINT) TTN_NEEDTEXTA) && (code != (UINT) TTN_NEEDTEXTW) )
921 return FALSE;
922
923 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
924 if ( toolTipWnd != hdr->hwndFrom )
925 return FALSE;
926
927 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
928 int id = (int)ttText->hdr.idFrom;
929
930 wxToolBarToolBase *tool = FindById(id);
931 if ( !tool )
932 return FALSE;
933
934 return HandleTooltipNotify(code, lParam, tool->GetShortHelp());
935#else
936 return FALSE;
937#endif
938}
939
940// ----------------------------------------------------------------------------
941// toolbar geometry
942// ----------------------------------------------------------------------------
943
944void wxToolBar::SetToolBitmapSize(const wxSize& size)
945{
946 wxToolBarBase::SetToolBitmapSize(size);
947
948 ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
949}
950
951void wxToolBar::SetRows(int nRows)
952{
953 if ( nRows == m_maxRows )
954 {
955 // avoid resizing the frame uselessly
956 return;
957 }
958
959 // TRUE in wParam means to create at least as many rows, FALSE -
960 // at most as many
961 RECT rect;
962 ::SendMessage(GetHwnd(), TB_SETROWS,
963 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
964 (LPARAM) &rect);
965
966 m_maxRows = nRows;
967
968 UpdateSize();
969}
970
971// The button size is bigger than the bitmap size
972wxSize wxToolBar::GetToolSize() const
973{
974 // TB_GETBUTTONSIZE is supported from version 4.70
975#if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \
976 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
977 if ( wxTheApp->GetComCtl32Version() >= 470 )
978 {
979 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
980
981 return wxSize(LOWORD(dw), HIWORD(dw));
982 }
983 else
984#endif // comctl32.dll 4.70+
985 {
986 // defaults
987 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
988 }
989}
990
991static
992wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
993 size_t index )
994{
995 wxToolBarToolsList::compatibility_iterator current = tools.GetFirst();
996
997 for ( ; current != 0; current = current->GetNext() )
998 {
999 if ( index == 0 )
1000 return current->GetData();
1001
1002 wxToolBarTool *tool = (wxToolBarTool *)current->GetData();
1003 size_t separators = tool->GetSeparatorsCount();
1004
1005 // if it is a normal button, sepcount == 0, so skip 1 item (the button)
1006 // otherwise, skip as many items as the separator count, plus the
1007 // control itself
1008 index -= separators ? separators + 1 : 1;
1009 }
1010
1011 return 0;
1012}
1013
1014wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
1015{
1016 POINT pt;
1017 pt.x = x;
1018 pt.y = y;
1019 int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
1020 // MBN: when the point ( x, y ) is close to the toolbar border
1021 // TB_HITTEST returns m_nButtons ( not -1 )
1022 if ( index < 0 || (size_t)index >= m_nButtons )
1023 {
1024 // it's a separator or there is no tool at all there
1025 return (wxToolBarToolBase *)NULL;
1026 }
1027
1028 // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers
1029#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
1030 if ( wxTheApp->GetComCtl32Version() >= 471 )
1031 {
1032 return m_tools.Item((size_t)index)->GetData();
1033 }
1034 else
1035#endif
1036 {
1037 return GetItemSkippingDummySpacers( m_tools, (size_t) index );
1038 }
1039}
1040
1041void wxToolBar::UpdateSize()
1042{
1043 // the toolbar size changed
1044 SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0);
1045
1046 // we must also refresh the frame after the toolbar size (possibly) changed
1047 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
1048 if ( frame )
1049 {
1050 frame->SendSizeEvent();
1051 }
1052}
1053
1054// ----------------------------------------------------------------------------
1055// toolbar styles
1056// ---------------------------------------------------------------------------
1057
1058void wxToolBar::SetWindowStyleFlag(long style)
1059{
1060 // the style bits whose changes force us to recreate the toolbar
1061 static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS;
1062
1063 const long styleOld = GetWindowStyle();
1064
1065 wxToolBarBase::SetWindowStyleFlag(style);
1066
1067 // don't recreate an empty toolbar: not only this is unnecessary, but it is
1068 // also fatal as we'd then try to recreate the toolbar when it's just being
1069 // created
1070 if ( GetToolsCount() &&
1071 (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
1072 {
1073 // to remove the text labels, simply re-realizing the toolbar is enough
1074 // but I don't know of any way to add the text to an existing toolbar
1075 // other than by recreating it entirely
1076 Recreate();
1077 }
1078}
1079
1080// ----------------------------------------------------------------------------
1081// tool state
1082// ----------------------------------------------------------------------------
1083
1084void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
1085{
1086 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
1087 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
1088}
1089
1090void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
1091{
1092 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
1093 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
1094}
1095
1096void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
1097{
1098 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
1099 // without, so we really need to delete the button and recreate it here
1100 wxFAIL_MSG( _T("not implemented") );
1101}
1102
1103// ----------------------------------------------------------------------------
1104// event handlers
1105// ----------------------------------------------------------------------------
1106
1107// Responds to colour changes, and passes event on to children.
1108void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
1109{
1110 wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));
1111
1112 // Remap the buttons
1113 Realize();
1114
1115 // Relayout the toolbar
1116 int nrows = m_maxRows;
1117 m_maxRows = 0; // otherwise SetRows() wouldn't do anything
1118 SetRows(nrows);
1119
1120 Refresh();
1121
1122 // let the event propagate further
1123 event.Skip();
1124}
1125
1126void wxToolBar::OnMouseEvent(wxMouseEvent& event)
1127{
1128 if (event.Leaving() && m_pInTool)
1129 {
1130 OnMouseEnter( -1 );
1131 event.Skip();
1132 return;
1133 }
1134
1135 if (event.RightDown())
1136 {
1137 // For now, we don't have an id. Later we could
1138 // try finding the tool.
1139 OnRightClick((int)-1, event.GetX(), event.GetY());
1140 }
1141 else
1142 {
1143 event.Skip();
1144 }
1145}
1146
1147void wxToolBar::HandleMouseMove(WXWPARAM wParam, WXLPARAM lParam)
1148{
1149 wxCoord x = GET_X_LPARAM(lParam),
1150 y = GET_Y_LPARAM(lParam);
1151 wxToolBarToolBase* tool = FindToolForPosition( x, y );
1152
1153 // cursor left current tool
1154 if( tool != m_pInTool && !tool )
1155 {
1156 m_pInTool = 0;
1157 OnMouseEnter( -1 );
1158 }
1159
1160 // cursor entered a tool
1161 if( tool != m_pInTool && tool )
1162 {
1163 m_pInTool = tool;
1164 OnMouseEnter( tool->GetId() );
1165 }
1166}
1167
1168long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1169{
1170#if 0
1171 switch ( nMsg )
1172 {
1173 case WM_SIZE:
1174 if ( HandleSize(wParam, lParam) )
1175 return 0;
1176 break;
1177
1178 case WM_MOUSEMOVE:
1179 // we don't handle mouse moves, so always pass the message to
1180 // wxControl::MSWWindowProc
1181 HandleMouseMove(wParam, lParam);
1182 break;
1183 }
1184#endif
1185 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
1186}
1187
1188// ----------------------------------------------------------------------------
1189// private functions
1190// ----------------------------------------------------------------------------
1191
1192WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height)
1193{
1194 MemoryHDC hdcMem;
1195
1196 if ( !hdcMem )
1197 {
1198 wxLogLastError(_T("CreateCompatibleDC"));
1199
1200 return bitmap;
1201 }
1202
1203 SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap);
1204
1205 if ( !bmpInHDC )
1206 {
1207 wxLogLastError(_T("SelectObject"));
1208
1209 return bitmap;
1210 }
1211
1212 wxCOLORMAP *cmap = wxGetStdColourMap();
1213
1214 for ( int i = 0; i < width; i++ )
1215 {
1216 for ( int j = 0; j < height; j++ )
1217 {
1218 COLORREF pixel = ::GetPixel(hdcMem, i, j);
1219
1220 for ( size_t k = 0; k < wxSTD_COL_MAX; k++ )
1221 {
1222 COLORREF col = cmap[k].from;
1223 if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 &&
1224 abs(GetGValue(pixel) - GetGValue(col)) < 10 &&
1225 abs(GetBValue(pixel) - GetBValue(col)) < 10 )
1226 {
1227 ::SetPixel(hdcMem, i, j, cmap[k].to);
1228 break;
1229 }
1230 }
1231 }
1232 }
1233
1234 return bitmap;
1235
1236 // VZ: I leave here my attempts to map the bitmap to the system colours
1237 // faster by using BitBlt() even though it's broken currently - but
1238 // maybe someone else can finish it? It should be faster than iterating
1239 // over all pixels...
1240#if 0
1241 MemoryHDC hdcMask, hdcDst;
1242 if ( !hdcMask || !hdcDst )
1243 {
1244 wxLogLastError(_T("CreateCompatibleDC"));
1245
1246 return bitmap;
1247 }
1248
1249 // create the target bitmap
1250 HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height);
1251 if ( !hbmpDst )
1252 {
1253 wxLogLastError(_T("CreateCompatibleBitmap"));
1254
1255 return bitmap;
1256 }
1257
1258 // create the monochrome mask bitmap
1259 HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0);
1260 if ( !hbmpMask )
1261 {
1262 wxLogLastError(_T("CreateBitmap(mono)"));
1263
1264 ::DeleteObject(hbmpDst);
1265
1266 return bitmap;
1267 }
1268
1269 SelectInHDC bmpInDst(hdcDst, hbmpDst),
1270 bmpInMask(hdcMask, hbmpMask);
1271
1272 // for each colour:
1273 for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ )
1274 {
1275 // create the mask for this colour
1276 ::SetBkColor(hdcMem, ColorMap[n].from);
1277 ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
1278
1279 // replace this colour with the target one in the dst bitmap
1280 HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to);
1281 HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr);
1282
1283 ::MaskBlt(hdcDst, 0, 0, width, height,
1284 hdcMem, 0, 0,
1285 hbmpMask, 0, 0,
1286 MAKEROP4(PATCOPY, SRCCOPY));
1287
1288 (void)::SelectObject(hdcDst, hbrOld);
1289 ::DeleteObject(hbr);
1290 }
1291
1292 ::DeleteObject((HBITMAP)bitmap);
1293
1294 return (WXHBITMAP)hbmpDst;
1295#endif // 0
1296}
1297
1298#endif // wxUSE_TOOLBAR && Win95
1299