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