]> git.saurik.com Git - wxWidgets.git/blob - src/msw/tbar95.cpp
Mostly Mingw32/Cygwin corrections
[wxWidgets.git] / src / msw / tbar95.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/tbar95.cpp
3 // Purpose: wxToolBar
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "tbar95.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 #endif
39
40 #if wxUSE_TOOLBAR && defined(__WIN95__) && wxUSE_TOOLBAR_NATIVE
41
42 #include "wx/toolbar.h"
43
44 #if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
45 #include "malloc.h"
46 #endif
47
48 #include "wx/msw/private.h"
49
50 #ifndef __TWIN32__
51
52 // I don't know what _OLD_ refers to so I'm reinstating the old
53 // ifdef (JACS).
54 // #ifdef __GNUWIN32_OLD__
55 #if defined(__GNUWIN32__) && !defined(__MINGW32__)
56 #include "wx/msw/gnuwin32/extra.h"
57 #else
58 #include <commctrl.h>
59 #endif
60
61 #endif // __TWIN32__
62
63 #include "wx/msw/dib.h"
64 #include "wx/app.h" // for GetComCtl32Version
65
66 // ----------------------------------------------------------------------------
67 // constants
68 // ----------------------------------------------------------------------------
69
70 // these standard constants are not always defined in compilers headers
71
72 // Styles
73 #ifndef TBSTYLE_FLAT
74 #define TBSTYLE_LIST 0x1000
75 #define TBSTYLE_FLAT 0x0800
76 #define TBSTYLE_TRANSPARENT 0x8000
77 #endif
78 // use TBSTYLE_TRANSPARENT if you use TBSTYLE_FLAT
79
80 // Messages
81 #ifndef TB_GETSTYLE
82 #define TB_SETSTYLE (WM_USER + 56)
83 #define TB_GETSTYLE (WM_USER + 57)
84 #endif
85
86 #ifndef TB_HITTEST
87 #define TB_HITTEST (WM_USER + 69)
88 #endif
89
90 // these values correspond to those used by comctl32.dll
91 #define DEFAULTBITMAPX 16
92 #define DEFAULTBITMAPY 15
93 #define DEFAULTBUTTONX 24
94 #define DEFAULTBUTTONY 24
95 #define DEFAULTBARHEIGHT 27
96
97 // ----------------------------------------------------------------------------
98 // private function prototypes
99 // ----------------------------------------------------------------------------
100
101 static void wxMapBitmap(HBITMAP hBitmap, int width, int height);
102
103 // ----------------------------------------------------------------------------
104 // wxWin macros
105 // ----------------------------------------------------------------------------
106
107 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
108
109 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
110 EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
111 EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
112 END_EVENT_TABLE()
113
114 // ----------------------------------------------------------------------------
115 // private classes
116 // ----------------------------------------------------------------------------
117
118 class wxToolBarTool : public wxToolBarToolBase
119 {
120 public:
121 wxToolBarTool(wxToolBar *tbar,
122 int id,
123 const wxBitmap& bitmap1,
124 const wxBitmap& bitmap2,
125 bool toggle,
126 wxObject *clientData,
127 const wxString& shortHelpString,
128 const wxString& longHelpString)
129 : wxToolBarToolBase(tbar, id, bitmap1, bitmap2, toggle,
130 clientData, shortHelpString, longHelpString)
131 {
132 m_nSepCount = 0;
133 }
134
135 wxToolBarTool(wxToolBar *tbar, wxControl *control)
136 : wxToolBarToolBase(tbar, control)
137 {
138 m_nSepCount = 1;
139 }
140
141 // set/get the number of separators which we use to cover the space used by
142 // a control in the toolbar
143 void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
144 size_t GetSeparatorsCount() const { return m_nSepCount; }
145
146 private:
147 size_t m_nSepCount;
148 };
149
150
151 // ============================================================================
152 // implementation
153 // ============================================================================
154
155 // ----------------------------------------------------------------------------
156 // wxToolBarTool
157 // ----------------------------------------------------------------------------
158
159 wxToolBarToolBase *wxToolBar::CreateTool(int id,
160 const wxBitmap& bitmap1,
161 const wxBitmap& bitmap2,
162 bool toggle,
163 wxObject *clientData,
164 const wxString& shortHelpString,
165 const wxString& longHelpString)
166 {
167 return new wxToolBarTool(this, id, bitmap1, bitmap2, toggle,
168 clientData, shortHelpString, longHelpString);
169 }
170
171 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
172 {
173 return new wxToolBarTool(this, control);
174 }
175
176 // ----------------------------------------------------------------------------
177 // wxToolBar construction
178 // ----------------------------------------------------------------------------
179
180 void wxToolBar::Init()
181 {
182 m_hBitmap = 0;
183
184 m_nButtons = 0;
185
186 m_defaultWidth = DEFAULTBITMAPX;
187 m_defaultHeight = DEFAULTBITMAPY;
188 }
189
190 bool wxToolBar::Create(wxWindow *parent,
191 wxWindowID id,
192 const wxPoint& pos,
193 const wxSize& size,
194 long style,
195 const wxString& name)
196 {
197 // common initialisation
198 if ( !CreateControl(parent, id, pos, size, style, name) )
199 return FALSE;
200
201 // prepare flags
202 DWORD msflags = 0; // WS_VISIBLE | WS_CHILD always included
203 if (style & wxBORDER)
204 msflags |= WS_BORDER;
205
206 #ifdef TBSTYLE_TOOLTIPS
207 msflags |= TBSTYLE_TOOLTIPS;
208 #endif
209
210 if (style & wxTB_FLAT)
211 {
212 if (wxTheApp->GetComCtl32Version() > 400)
213 msflags |= TBSTYLE_FLAT;
214 }
215
216 // MSW-specific initialisation
217 if ( !wxControl::MSWCreateControl(TOOLBARCLASSNAME, msflags) )
218 return FALSE;
219
220 // toolbar-specific post initialisation
221 ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
222
223 // set up the colors and fonts
224 wxRGBToColour(m_backgroundColour, GetSysColor(COLOR_BTNFACE));
225 m_foregroundColour = *wxBLACK;
226
227 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
228
229 // position it
230 int x = pos.x;
231 int y = pos.y;
232 int width = size.x;
233 int height = size.y;
234
235 if (width <= 0)
236 width = 100;
237 if (height <= 0)
238 height = m_defaultHeight;
239 if (x < 0)
240 x = 0;
241 if (y < 0)
242 y = 0;
243
244 SetSize(x, y, width, height);
245
246 return TRUE;
247 }
248
249 wxToolBar::~wxToolBar()
250 {
251 if (m_hBitmap)
252 {
253 ::DeleteObject((HBITMAP) m_hBitmap);
254 }
255 }
256
257 // ----------------------------------------------------------------------------
258 // adding/removing tools
259 // ----------------------------------------------------------------------------
260
261 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
262 wxToolBarToolBase *tool)
263 {
264 // nothing special to do here - we really create the toolbar buttons in
265 // Realize() later
266 tool->Attach(this);
267
268 return TRUE;
269 }
270
271 bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
272 {
273 // normally, we only delete one button, but we use several separators to
274 // cover the space used by one control sometimes (with old comctl32.dll)
275 size_t nButtonsToDelete = 1;
276
277 // get the size of the button we're going to delete
278 RECT r;
279 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
280 {
281 wxLogLastError(_T("TB_GETITEMRECT"));
282 }
283
284 int width = r.right - r.left;
285
286 if ( tool->IsControl() )
287 {
288 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
289
290 width *= nButtonsToDelete;
291 }
292
293 while ( nButtonsToDelete-- > 0 )
294 {
295 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
296 {
297 wxLogLastError("TB_DELETEBUTTON");
298
299 return FALSE;
300 }
301 }
302
303 tool->Detach();
304
305 m_nButtons -= nButtonsToDelete;
306
307 // reposition all the controls after this button
308 wxToolBarToolsList::Node *node = m_tools.Item(pos);
309 for ( node = node->GetNext(); node; node = node->GetNext() )
310 {
311 wxToolBarToolBase *tool2 = node->GetData();
312 if ( tool2->IsControl() )
313 {
314 int x;
315 wxControl *control = tool2->GetControl();
316 control->GetPosition(&x, NULL);
317 control->Move(x - width, -1);
318 }
319 }
320
321 return TRUE;
322 }
323
324 bool wxToolBar::Realize()
325 {
326 size_t nTools = GetToolsCount();
327 if ( nTools == 0 )
328 {
329 // nothing to do
330 return TRUE;
331 }
332
333 bool isVertical = (GetWindowStyle() & wxTB_VERTICAL) != 0;
334
335 // First, add the bitmap: we use one bitmap for all toolbar buttons
336 // ----------------------------------------------------------------
337
338 // if we already have a bitmap, we'll replace the existing one - otherwise
339 // we'll install a new one
340 HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
341
342 int totalBitmapWidth = (int)(m_defaultWidth * nTools);
343 int totalBitmapHeight = (int)m_defaultHeight;
344
345 // Create a bitmap for all the tool bitmaps
346 HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
347 totalBitmapWidth,
348 totalBitmapHeight);
349 if ( !hBitmap )
350 {
351 wxLogLastError(_T("CreateCompatibleBitmap"));
352
353 return FALSE;
354 }
355
356 m_hBitmap = (WXHBITMAP)hBitmap;
357
358 // Now blit all the tools onto this bitmap
359 HDC memoryDC = ::CreateCompatibleDC(NULL);
360 HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, hBitmap);
361
362 HDC memoryDC2 = ::CreateCompatibleDC(NULL);
363
364 // the button position
365 wxCoord x = 0;
366
367 // the number of buttons (not separators)
368 int nButtons = 0;
369
370 wxToolBarToolsList::Node *node = m_tools.GetFirst();
371 while ( node )
372 {
373 wxToolBarToolBase *tool = node->GetData();
374 if ( tool->IsButton() )
375 {
376 HBITMAP hbmp = GetHbitmapOf(tool->GetBitmap1());
377 if ( hbmp )
378 {
379 HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp);
380 if ( !BitBlt(memoryDC, x, 0, m_defaultWidth, m_defaultHeight,
381 memoryDC2, 0, 0, SRCCOPY) )
382 {
383 wxLogLastError("BitBlt");
384 }
385
386 ::SelectObject(memoryDC2, oldBitmap2);
387 }
388 else
389 {
390 wxFAIL_MSG( _T("invalid tool button bitmap") );
391 }
392
393 // still inc width and number of buttons because otherwise the
394 // subsequent buttons will all be shifted which is rather confusing
395 // (and like this you'd see immediately which bitmap was bad)
396 x += m_defaultWidth;
397 nButtons++;
398 }
399
400 node = node->GetNext();
401 }
402
403 ::SelectObject(memoryDC, oldBitmap);
404 ::DeleteDC(memoryDC);
405 ::DeleteDC(memoryDC2);
406
407 // Map to system colours
408 wxMapBitmap(hBitmap, totalBitmapWidth, totalBitmapHeight);
409
410 if ( oldToolBarBitmap )
411 {
412 TBREPLACEBITMAP replaceBitmap;
413 replaceBitmap.hInstOld = NULL;
414 replaceBitmap.hInstNew = NULL;
415 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
416 replaceBitmap.nIDNew = (UINT) hBitmap;
417 replaceBitmap.nButtons = nButtons;
418 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
419 0, (LPARAM) &replaceBitmap) )
420 {
421 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
422 }
423
424 ::DeleteObject(oldToolBarBitmap);
425
426 // Now delete all the buttons
427 for ( size_t pos = 0; pos < m_nButtons; pos++ )
428 {
429 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
430 {
431 wxLogLastError("TB_DELETEBUTTON");
432 }
433 }
434 }
435 else // no old bitmap
436 {
437 TBADDBITMAP addBitmap;
438 addBitmap.hInst = 0;
439 addBitmap.nID = (UINT) hBitmap;
440 if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
441 (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
442 {
443 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
444 }
445 }
446
447 // Next add the buttons and separators
448 // -----------------------------------
449
450 TBBUTTON *buttons = new TBBUTTON[nTools];
451
452 // this array will hold the indices of all controls in the toolbar
453 wxArrayInt controlIds;
454
455 int i = 0;
456 int bitmapId = 0;
457
458 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
459 {
460 wxToolBarToolBase *tool = node->GetData();
461
462 // don't add separators to the vertical toolbar - looks ugly
463 if ( isVertical && tool->IsSeparator() )
464 continue;
465
466 TBBUTTON& button = buttons[i];
467
468 wxZeroMemory(button);
469
470 switch ( tool->GetStyle() )
471 {
472 case wxTOOL_STYLE_CONTROL:
473 button.idCommand = tool->GetId();
474 // fall through: create just a separator too
475
476 case wxTOOL_STYLE_SEPARATOR:
477 button.fsState = TBSTATE_ENABLED;
478 button.fsStyle = TBSTYLE_SEP;
479 break;
480
481 case wxTOOL_STYLE_BUTTON:
482 button.iBitmap = bitmapId;
483 button.idCommand = tool->GetId();
484
485 if ( tool->IsEnabled() )
486 button.fsState |= TBSTATE_ENABLED;
487 if ( tool->IsToggled() )
488 button.fsState |= TBSTATE_CHECKED;
489
490 button.fsStyle = tool->CanBeToggled() ? TBSTYLE_CHECK
491 : TBSTYLE_BUTTON;
492
493 bitmapId++;
494 break;
495 }
496
497 i++;
498 }
499
500 if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS,
501 (WPARAM)i, (LPARAM)buttons) )
502 {
503 wxLogLastError("TB_ADDBUTTONS");
504 }
505
506 delete [] buttons;
507
508 // Deal with the controls finally
509 // ------------------------------
510
511 // adjust the controls size to fit nicely in the toolbar
512 size_t index = 0;
513 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
514 {
515 wxToolBarToolBase *tool = node->GetData();
516 if ( !tool->IsControl() )
517 continue;
518
519 wxControl *control = tool->GetControl();
520
521 wxSize size = control->GetSize();
522
523 // the position of the leftmost controls corner
524 int left = -1;
525
526 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
527 // latter only appeared in v4.70 of comctl32.dll
528 RECT r;
529 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
530 index, (LPARAM)(LPRECT)&r) )
531 {
532 wxLogLastError("TB_GETITEMRECT");
533 }
534
535 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
536 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
537 // available in headers, now check whether it is available now
538 // (during run-time)
539 if ( wxTheApp->GetComCtl32Version() >= 471 )
540 {
541 // set the (underlying) separators width to be that of the
542 // control
543 TBBUTTONINFO tbbi;
544 tbbi.cbSize = sizeof(tbbi);
545 tbbi.dwMask = TBIF_SIZE;
546 tbbi.cx = size.x;
547 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
548 tool->GetId(), (LPARAM)&tbbi) )
549 {
550 // the id is probably invalid?
551 wxLogLastError("TB_SETBUTTONINFO");
552 }
553
554 }
555 else
556 #endif // comctl32.dll 4.71
557 // TB_SETBUTTONINFO unavailable
558 {
559 // try adding several separators to fit the controls width
560 int widthSep = r.right - r.left;
561 left = r.left;
562
563 TBBUTTON tbb;
564 wxZeroMemory(tbb);
565 tbb.idCommand = 0;
566 tbb.fsState = TBSTATE_ENABLED;
567 tbb.fsStyle = TBSTYLE_SEP;
568
569 size_t nSeparators = size.x / widthSep;
570 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
571 {
572 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
573 index, (LPARAM)&tbb) )
574 {
575 wxLogLastError("TB_INSERTBUTTON");
576 }
577
578 index++;
579 }
580
581 // remember the number of separators we used - we'd have to
582 // delete all of them later
583 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
584
585 // adjust the controls width to exactly cover the separators
586 control->SetSize((nSeparators + 1)*widthSep, -1);
587 }
588
589 // and position the control itself correctly vertically
590 int height = r.bottom - r.top;
591 int diff = height - size.y;
592 if ( diff < 0 )
593 {
594 // the control is too high, resize to fit
595 control->SetSize(-1, height - 2);
596
597 diff = 2;
598 }
599
600 control->Move(left == -1 ? r.left : left, r.top + (diff + 1) / 2);
601 }
602
603 // the max index is the "real" number of buttons - i.e. counting even the
604 // separators which we added just for aligning the controls
605 m_nButtons = index;
606
607 if ( !isVertical )
608 {
609 if ( m_maxRows == 0 )
610 {
611 // if not set yet, only one row
612 SetRows(1);
613 }
614 }
615 else if ( m_nButtons > 0 ) // vertical non empty toolbar
616 {
617 if ( m_maxRows == 0 )
618 {
619 // if not set yet, have one column
620 SetRows(m_nButtons);
621 }
622 }
623
624 return TRUE;
625 }
626
627 // ----------------------------------------------------------------------------
628 // message handlers
629 // ----------------------------------------------------------------------------
630
631 bool wxToolBar::MSWCommand(WXUINT cmd, WXWORD id)
632 {
633 wxToolBarToolBase *tool = FindById((int)id);
634 if ( !tool )
635 return FALSE;
636
637 if ( tool->CanBeToggled() )
638 {
639 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
640 tool->SetToggle((state & TBSTATE_CHECKED) != 0);
641 }
642
643 bool toggled = tool->IsToggled();
644
645 // OnLeftClick() can veto the button state change - for buttons which may
646 // be toggled only, of couse
647 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
648 {
649 // revert back
650 toggled = !toggled;
651 tool->SetToggle(toggled);
652
653 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
654 }
655
656 return TRUE;
657 }
658
659 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
660 WXLPARAM lParam,
661 WXLPARAM *result)
662 {
663 // First check if this applies to us
664 NMHDR *hdr = (NMHDR *)lParam;
665
666 // the tooltips control created by the toolbar is sometimes Unicode, even
667 // in an ANSI application - this seems to be a bug in comctl32.dll v5
668 int code = (int)hdr->code;
669 if ( (code != TTN_NEEDTEXTA) && (code != TTN_NEEDTEXTW) )
670 return FALSE;
671
672 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
673 if ( toolTipWnd != hdr->hwndFrom )
674 return FALSE;
675
676 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
677 int id = (int)ttText->hdr.idFrom;
678
679 wxToolBarToolBase *tool = FindById(id);
680 if ( !tool )
681 return FALSE;
682
683 const wxString& help = tool->GetShortHelp();
684
685 if ( !help.IsEmpty() )
686 {
687 if ( code == TTN_NEEDTEXTA )
688 {
689 ttText->lpszText = (wxChar *)help.c_str();
690 }
691 #if (_WIN32_IE >= 0x0300)
692 else
693 {
694 // FIXME this is a temp hack only until I understand better what
695 // must be done in both ANSI and Unicode builds
696
697 size_t lenAnsi = help.Len();
698 #ifdef __MWERKS__
699 // MetroWerks doesn't like calling mbstowcs with NULL argument
700 size_t lenUnicode = 2*lenAnsi;
701 #else
702 size_t lenUnicode = mbstowcs(NULL, help, lenAnsi);
703 #endif
704
705 // using the pointer of right type avoids us doing all sorts of
706 // pointer arithmetics ourselves
707 wchar_t *dst = (wchar_t *)ttText->szText,
708 *pwz = new wchar_t[lenUnicode + 1];
709 mbstowcs(pwz, help, lenAnsi + 1);
710 memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
711
712 // put the terminating _wide_ NUL
713 dst[lenUnicode] = 0;
714
715 delete [] pwz;
716 }
717 #endif // _WIN32_IE >= 0x0300
718 }
719
720 // For backward compatibility...
721 OnMouseEnter(tool->GetId());
722
723 return TRUE;
724 }
725
726 // ----------------------------------------------------------------------------
727 // toolbar geometry
728 // ----------------------------------------------------------------------------
729
730 void wxToolBar::SetToolBitmapSize(const wxSize& size)
731 {
732 wxToolBarBase::SetToolBitmapSize(size);
733
734 ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
735 }
736
737 void wxToolBar::SetRows(int nRows)
738 {
739 if ( nRows == m_maxRows )
740 {
741 // avoid resizing the frame uselessly
742 return;
743 }
744
745 // TRUE in wParam means to create at least as many rows, FALSE -
746 // at most as many
747 RECT rect;
748 ::SendMessage(GetHwnd(), TB_SETROWS,
749 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
750 (LPARAM) &rect);
751
752 m_maxRows = nRows;
753
754 UpdateSize();
755 }
756
757 // The button size is bigger than the bitmap size
758 wxSize wxToolBar::GetToolSize() const
759 {
760 // TB_GETBUTTONSIZE is supported from version 4.70
761 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 )
762 if ( wxTheApp->GetComCtl32Version() >= 470 )
763 {
764 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
765
766 return wxSize(LOWORD(dw), HIWORD(dw));
767 }
768 else
769 #endif // comctl32.dll 4.70+
770 {
771 // defaults
772 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
773 }
774 }
775
776 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
777 {
778 POINT pt;
779 pt.x = x;
780 pt.y = y;
781 int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
782 if ( index < 0 )
783 {
784 // it's a separator or there is no tool at all there
785 return (wxToolBarToolBase *)NULL;
786 }
787
788 return m_tools.Item((size_t)index)->GetData();
789 }
790
791 void wxToolBar::UpdateSize()
792 {
793 // we must refresh the frame after the toolbar size (possibly) changed
794 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
795 if ( frame )
796 {
797 // don't change the size, we just need to generate a WM_SIZE
798 RECT r;
799 if ( !GetWindowRect(GetHwndOf(frame), &r) )
800 {
801 wxLogLastError(_T("GetWindowRect"));
802 }
803
804 (void)::SendMessage(GetHwndOf(frame), WM_SIZE, SIZE_RESTORED,
805 MAKELPARAM(r.right - r.left, r.bottom - r.top));
806 }
807
808 }
809
810 // ----------------------------------------------------------------------------
811 // tool state
812 // ----------------------------------------------------------------------------
813
814 void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
815 {
816 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
817 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
818 }
819
820 void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
821 {
822 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
823 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
824 }
825
826 void wxToolBar::DoSetToggle(wxToolBarToolBase *tool, bool toggle)
827 {
828 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
829 // without, so we really need to delete the button and recreate it here
830 wxFAIL_MSG( _T("not implemented") );
831 }
832
833 // ----------------------------------------------------------------------------
834 // event handlers
835 // ----------------------------------------------------------------------------
836
837 // Responds to colour changes, and passes event on to children.
838 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
839 {
840 m_backgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
841 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
842
843 // Remap the buttons
844 Realize();
845
846 Refresh();
847
848 // Propagate the event to the non-top-level children
849 wxWindow::OnSysColourChanged(event);
850 }
851
852 void wxToolBar::OnMouseEvent(wxMouseEvent& event)
853 {
854 if (event.RightDown())
855 {
856 // For now, we don't have an id. Later we could
857 // try finding the tool.
858 OnRightClick((int)-1, event.GetX(), event.GetY());
859 }
860 else
861 {
862 event.Skip();
863 }
864 }
865
866 long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
867 {
868 if ( nMsg == WM_SIZE )
869 {
870 // calculate our minor dimenstion ourselves - we're confusing the
871 // standard logic (TB_AUTOSIZE) with our horizontal toolbars and other
872 // hacks
873 RECT r;
874 if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) )
875 {
876 int w, h;
877
878 if ( GetWindowStyle() & wxTB_VERTICAL )
879 {
880 w = r.right - r.left;
881 if ( m_maxRows )
882 {
883 w *= (m_nButtons + m_maxRows - 1)/m_maxRows;
884 }
885 h = HIWORD(lParam);
886 }
887 else
888 {
889 w = LOWORD(lParam);
890 h = r.bottom - r.top;
891 if ( m_maxRows )
892 {
893 h += 6; // FIXME: this is the separator line height...
894 h *= m_maxRows;
895 }
896 }
897
898 if ( MAKELPARAM(w, h) != lParam )
899 {
900 // size really changed
901 SetSize(w, h);
902 }
903
904 // message processed
905 return 0;
906 }
907 }
908
909 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
910 }
911
912 // ----------------------------------------------------------------------------
913 // private functions
914 // ----------------------------------------------------------------------------
915
916 // These are the default colors used to map the bitmap colors to the current
917 // system colors. Note that they are in BGR format because this is what Windows
918 // wants (and not RGB)
919
920 #define BGR_BUTTONTEXT (RGB(000,000,000)) // black
921 #define BGR_BUTTONSHADOW (RGB(128,128,128)) // dark grey
922 #define BGR_BUTTONFACE (RGB(192,192,192)) // bright grey
923 #define BGR_BUTTONHILIGHT (RGB(255,255,255)) // white
924 #define BGR_BACKGROUNDSEL (RGB(255,000,000)) // blue
925 #define BGR_BACKGROUND (RGB(255,000,255)) // magenta
926
927 void wxMapBitmap(HBITMAP hBitmap, int width, int height)
928 {
929 COLORMAP ColorMap[] =
930 {
931 {BGR_BUTTONTEXT, COLOR_BTNTEXT}, // black
932 {BGR_BUTTONSHADOW, COLOR_BTNSHADOW}, // dark grey
933 {BGR_BUTTONFACE, COLOR_BTNFACE}, // bright grey
934 {BGR_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT},// white
935 {BGR_BACKGROUNDSEL, COLOR_HIGHLIGHT}, // blue
936 {BGR_BACKGROUND, COLOR_WINDOW} // magenta
937 };
938
939 int NUM_MAPS = (sizeof(ColorMap)/sizeof(COLORMAP));
940 int n;
941 for ( n = 0; n < NUM_MAPS; n++)
942 {
943 ColorMap[n].to = ::GetSysColor(ColorMap[n].to);
944 }
945
946 HBITMAP hbmOld;
947 HDC hdcMem = CreateCompatibleDC(NULL);
948
949 if (hdcMem)
950 {
951 hbmOld = (HBITMAP) SelectObject(hdcMem, hBitmap);
952
953 int i, j, k;
954 for ( i = 0; i < width; i++)
955 {
956 for ( j = 0; j < height; j++)
957 {
958 COLORREF pixel = ::GetPixel(hdcMem, i, j);
959 /*
960 BYTE red = GetRValue(pixel);
961 BYTE green = GetGValue(pixel);
962 BYTE blue = GetBValue(pixel);
963 */
964
965 for ( k = 0; k < NUM_MAPS; k ++)
966 {
967 if ( ColorMap[k].from == pixel )
968 {
969 /* COLORREF actualPixel = */ ::SetPixel(hdcMem, i, j, ColorMap[k].to);
970 break;
971 }
972 }
973 }
974 }
975
976
977 SelectObject(hdcMem, hbmOld);
978 DeleteObject(hdcMem);
979 }
980
981 }
982
983 // Some experiments...
984 #if 0
985 // What we want to do is create another bitmap which has a depth of 4,
986 // and set the bits. So probably we want to convert this HBITMAP into a
987 // DIB, then call SetDIBits.
988 // AAAGH. The stupid thing is that if newBitmap has a depth of 4 (less than that of
989 // the screen), then SetDIBits fails.
990 HBITMAP newBitmap = ::CreateBitmap(totalBitmapWidth, totalBitmapHeight, 1, 4, NULL);
991 HANDLE newDIB = ::BitmapToDIB((HBITMAP) m_hBitmap, NULL);
992 LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) GlobalLock(newDIB);
993
994 dc = ::GetDC(NULL);
995 // LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) newDIB;
996
997 int result = ::SetDIBits(dc, newBitmap, 0, lpbmi->biHeight, FindDIBBits((LPSTR)lpbmi), (LPBITMAPINFO)lpbmi,
998 DIB_PAL_COLORS);
999 DWORD err = GetLastError();
1000
1001 ::ReleaseDC(NULL, dc);
1002
1003 // Delete the DIB
1004 GlobalUnlock (newDIB);
1005 GlobalFree (newDIB);
1006
1007 // WXHBITMAP hBitmap2 = wxCreateMappedBitmap((WXHINSTANCE) wxGetInstance(), (WXHBITMAP) m_hBitmap);
1008 // Substitute our new bitmap for the old one
1009 ::DeleteObject((HBITMAP) m_hBitmap);
1010 m_hBitmap = (WXHBITMAP) newBitmap;
1011 #endif
1012
1013
1014 #endif // wxUSE_TOOLBAR && Win95