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