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