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