]> git.saurik.com Git - wxWidgets.git/blob - src/os2/toolbar.cpp
fix for a crash in ~wxFontList
[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 , wxDefaultValidator
191 ,rName
192 ))
193 return(FALSE);
194
195 // prepare flags
196 DWORD msflags = 0; // WS_VISIBLE | WS_CHILD always included
197 // TODO
198 /*
199
200 if (lStyle & 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 ::GpiDeleteBitmap((HBITMAP) m_hBitmap);
248 }
249 }
250
251 // ----------------------------------------------------------------------------
252 // adding/removing tools
253 // ----------------------------------------------------------------------------
254
255 bool wxToolBar::DoInsertTool(
256 size_t WXUNUSED(nPos)
257 , wxToolBarToolBase* pTool
258 )
259 {
260 // nothing special to do here - we really create the toolbar buttons in
261 // Realize() later
262 pTool->Attach(this);
263 return(TRUE);
264 }
265
266 bool wxToolBar::DoDeleteTool(
267 size_t nPos
268 , wxToolBarToolBase* pTool
269 )
270 {
271 // normally, we only delete one button, but we use several separators to
272 // cover the space used by one control sometimes (with old comctl32.dll)
273 size_t nButtonsToDelete = 1;
274
275 // get the size of the button we're going to delete
276 RECTL vRect;
277
278 // TODO:
279 /*
280 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
281 {
282 wxLogLastError(_T("TB_GETITEMRECT"));
283 }
284
285 int width = r.right - r.left;
286
287 if ( tool->IsControl() )
288 {
289 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
290
291 width *= nButtonsToDelete;
292 }
293
294 while ( nButtonsToDelete-- > 0 )
295 {
296 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
297 {
298 wxLogLastError("TB_DELETEBUTTON");
299
300 return FALSE;
301 }
302 }
303
304 tool->Detach();
305
306 m_nButtons -= nButtonsToDelete;
307
308 // reposition all the controls after this button
309 wxToolBarToolsList::Node *node = m_tools.Item(pos);
310 for ( node = node->GetNext(); node; node = node->GetNext() )
311 {
312 wxToolBarToolBase *tool2 = node->GetData();
313 if ( tool2->IsControl() )
314 {
315 int x;
316 wxControl *control = tool2->GetControl();
317 control->GetPosition(&x, NULL);
318 control->Move(x - width, -1);
319 }
320 }
321 */
322 return(TRUE);
323 }
324
325 bool wxToolBar::Realize()
326 {
327 size_t nTools = GetToolsCount();
328
329 if (nTools == 0)
330 {
331 // nothing to do
332 return(TRUE);
333 }
334
335 bool bIsVertical = (GetWindowStyle() & wxTB_VERTICAL) != 0;
336
337 // TODO:
338 /*
339 // First, add the bitmap: we use one bitmap for all toolbar buttons
340 // ----------------------------------------------------------------
341
342 // if we already have a bitmap, we'll replace the existing one - otherwise
343 // we'll install a new one
344 HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
345
346 int totalBitmapWidth = (int)(m_defaultWidth * nTools);
347 int totalBitmapHeight = (int)m_defaultHeight;
348
349 // Create a bitmap for all the tool bitmaps
350 HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
351 totalBitmapWidth,
352 totalBitmapHeight);
353 if ( !hBitmap )
354 {
355 wxLogLastError(_T("CreateCompatibleBitmap"));
356
357 return FALSE;
358 }
359
360 m_hBitmap = (WXHBITMAP)hBitmap;
361
362 // Now blit all the tools onto this bitmap
363 HDC memoryDC = ::CreateCompatibleDC(NULL);
364 HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, hBitmap);
365
366 HDC memoryDC2 = ::CreateCompatibleDC(NULL);
367
368 // the button position
369 wxCoord x = 0;
370
371 // the number of buttons (not separators)
372 int nButtons = 0;
373
374 wxToolBarToolsList::Node *node = m_tools.GetFirst();
375 while ( node )
376 {
377 wxToolBarToolBase *tool = node->GetData();
378 if ( tool->IsButton() )
379 {
380 HBITMAP hbmp = GetHbitmapOf(tool->GetBitmap1());
381 if ( hbmp )
382 {
383 HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp);
384 if ( !BitBlt(memoryDC, x, 0, m_defaultWidth, m_defaultHeight,
385 memoryDC2, 0, 0, SRCCOPY) )
386 {
387 wxLogLastError("BitBlt");
388 }
389
390 ::SelectObject(memoryDC2, oldBitmap2);
391 }
392 else
393 {
394 wxFAIL_MSG( _T("invalid tool button bitmap") );
395 }
396
397 // still inc width and number of buttons because otherwise the
398 // subsequent buttons will all be shifted which is rather confusing
399 // (and like this you'd see immediately which bitmap was bad)
400 x += m_defaultWidth;
401 nButtons++;
402 }
403
404 node = node->GetNext();
405 }
406
407 ::SelectObject(memoryDC, oldBitmap);
408 ::DeleteDC(memoryDC);
409 ::DeleteDC(memoryDC2);
410
411 // Map to system colours
412 wxMapBitmap(hBitmap, totalBitmapWidth, totalBitmapHeight);
413
414 if ( oldToolBarBitmap )
415 {
416 TBREPLACEBITMAP replaceBitmap;
417 replaceBitmap.hInstOld = NULL;
418 replaceBitmap.hInstNew = NULL;
419 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
420 replaceBitmap.nIDNew = (UINT) hBitmap;
421 replaceBitmap.nButtons = nButtons;
422 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
423 0, (LPARAM) &replaceBitmap) )
424 {
425 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
426 }
427
428 ::DeleteObject(oldToolBarBitmap);
429
430 // Now delete all the buttons
431 for ( size_t pos = 0; pos < m_nButtons; pos++ )
432 {
433 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
434 {
435 wxLogLastError("TB_DELETEBUTTON");
436 }
437 }
438 }
439 else // no old bitmap
440 {
441 TBADDBITMAP addBitmap;
442 addBitmap.hInst = 0;
443 addBitmap.nID = (UINT) hBitmap;
444 if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
445 (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
446 {
447 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
448 }
449 }
450
451 // Next add the buttons and separators
452 // -----------------------------------
453
454 TBBUTTON *buttons = new TBBUTTON[nTools];
455
456 // this array will hold the indices of all controls in the toolbar
457 wxArrayInt controlIds;
458
459 int i = 0;
460 int bitmapId = 0;
461
462 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
463 {
464 wxToolBarToolBase *tool = node->GetData();
465
466 // don't add separators to the vertical toolbar - looks ugly
467 if ( isVertical && tool->IsSeparator() )
468 continue;
469
470 TBBUTTON& button = buttons[i];
471
472 wxZeroMemory(button);
473
474 switch ( tool->GetStyle() )
475 {
476 case wxTOOL_STYLE_CONTROL:
477 button.idCommand = tool->GetId();
478 // fall through: create just a separator too
479
480 case wxTOOL_STYLE_SEPARATOR:
481 button.fsState = TBSTATE_ENABLED;
482 button.fsStyle = TBSTYLE_SEP;
483 break;
484
485 case wxTOOL_STYLE_BUTTON:
486 button.iBitmap = bitmapId;
487 button.idCommand = tool->GetId();
488
489 if ( tool->IsEnabled() )
490 button.fsState |= TBSTATE_ENABLED;
491 if ( tool->IsToggled() )
492 button.fsState |= TBSTATE_CHECKED;
493
494 button.fsStyle = tool->CanBeToggled() ? TBSTYLE_CHECK
495 : TBSTYLE_BUTTON;
496
497 bitmapId++;
498 break;
499 }
500
501 i++;
502 }
503
504 if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS,
505 (WPARAM)i, (LPARAM)buttons) )
506 {
507 wxLogLastError("TB_ADDBUTTONS");
508 }
509
510 delete [] buttons;
511
512 // Deal with the controls finally
513 // ------------------------------
514
515 // adjust the controls size to fit nicely in the toolbar
516 size_t index = 0;
517 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
518 {
519 wxToolBarToolBase *tool = node->GetData();
520 if ( !tool->IsControl() )
521 continue;
522
523 wxControl *control = tool->GetControl();
524
525 wxSize size = control->GetSize();
526
527 // the position of the leftmost controls corner
528 int left = -1;
529
530 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
531 // latter only appeared in v4.70 of comctl32.dll
532 RECT r;
533 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
534 index, (LPARAM)(LPRECT)&r) )
535 {
536 wxLogLastError("TB_GETITEMRECT");
537 }
538
539 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
540 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
541 // available in headers, now check whether it is available now
542 // (during run-time)
543 if ( wxTheApp->GetComCtl32Version() >= 471 )
544 {
545 // set the (underlying) separators width to be that of the
546 // control
547 TBBUTTONINFO tbbi;
548 tbbi.cbSize = sizeof(tbbi);
549 tbbi.dwMask = TBIF_SIZE;
550 tbbi.cx = size.x;
551 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
552 tool->GetId(), (LPARAM)&tbbi) )
553 {
554 // the id is probably invalid?
555 wxLogLastError("TB_SETBUTTONINFO");
556 }
557
558 }
559 else
560 #endif // comctl32.dll 4.71
561 // TB_SETBUTTONINFO unavailable
562 {
563 // try adding several separators to fit the controls width
564 int widthSep = r.right - r.left;
565 left = r.left;
566
567 TBBUTTON tbb;
568 wxZeroMemory(tbb);
569 tbb.idCommand = 0;
570 tbb.fsState = TBSTATE_ENABLED;
571 tbb.fsStyle = TBSTYLE_SEP;
572
573 size_t nSeparators = size.x / widthSep;
574 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
575 {
576 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
577 index, (LPARAM)&tbb) )
578 {
579 wxLogLastError("TB_INSERTBUTTON");
580 }
581
582 index++;
583 }
584
585 // remember the number of separators we used - we'd have to
586 // delete all of them later
587 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
588
589 // adjust the controls width to exactly cover the separators
590 control->SetSize((nSeparators + 1)*widthSep, -1);
591 }
592
593 // and position the control itself correctly vertically
594 int height = r.bottom - r.top;
595 int diff = height - size.y;
596 if ( diff < 0 )
597 {
598 // the control is too high, resize to fit
599 control->SetSize(-1, height - 2);
600
601 diff = 2;
602 }
603
604 control->Move(left == -1 ? r.left : left, r.top + (diff + 1) / 2);
605 }
606
607 // the max index is the "real" number of buttons - i.e. counting even the
608 // separators which we added just for aligning the controls
609 m_nButtons = index;
610
611 if ( !isVertical )
612 {
613 if ( m_maxRows == 0 )
614 {
615 // if not set yet, only one row
616 SetRows(1);
617 }
618 }
619 else if ( m_nButtons > 0 ) // vertical non empty toolbar
620 {
621 if ( m_maxRows == 0 )
622 {
623 // if not set yet, have one column
624 SetRows(m_nButtons);
625 }
626 }
627 */
628 return TRUE;
629 }
630
631 // ----------------------------------------------------------------------------
632 // message handlers
633 // ----------------------------------------------------------------------------
634
635 bool wxToolBar::OS2Command(
636 WXUINT nCmd
637 , WXWORD nId
638 )
639 {
640 wxToolBarToolBase* pTool = FindById((int)nId);
641
642 if (!pTool)
643 return(FALSE);
644 // TODO:
645 /*
646 if (pTool->CanBeToggled())
647 {
648 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
649 tool->SetToggle((state & TBSTATE_CHECKED) != 0);
650 }
651
652 bool toggled = tool->IsToggled();
653
654 // OnLeftClick() can veto the button state change - for buttons which may
655 // be toggled only, of couse
656 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
657 {
658 // revert back
659 toggled = !toggled;
660 tool->SetToggle(toggled);
661
662 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
663 }
664 */
665 return(TRUE);
666 }
667
668 bool wxToolBar::OS2OnNotify(
669 int WXUNUSED(idCtrl)
670 , WXLPARAM lParam
671 , WXLPARAM* pResult
672 )
673 {
674 // TODO:
675 /*
676 // First check if this applies to us
677 NMHDR *hdr = (NMHDR *)lParam;
678
679 // the tooltips control created by the toolbar is sometimes Unicode, even
680 // in an ANSI application - this seems to be a bug in comctl32.dll v5
681 int code = (int)hdr->code;
682 if ( (code != TTN_NEEDTEXTA) && (code != TTN_NEEDTEXTW) )
683 return FALSE;
684
685 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
686 if ( toolTipWnd != hdr->hwndFrom )
687 return FALSE;
688
689 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
690 int id = (int)ttText->hdr.idFrom;
691
692 wxToolBarToolBase *tool = FindById(id);
693 if ( !tool )
694 return FALSE;
695
696 const wxString& help = tool->GetShortHelp();
697
698 if ( !help.IsEmpty() )
699 {
700 if ( code == TTN_NEEDTEXTA )
701 {
702 ttText->lpszText = (wxChar *)help.c_str();
703 }
704 #if (_WIN32_IE >= 0x0300)
705 else
706 {
707 // FIXME this is a temp hack only until I understand better what
708 // must be done in both ANSI and Unicode builds
709
710 size_t lenAnsi = help.Len();
711 #ifdef __MWERKS__
712 // MetroWerks doesn't like calling mbstowcs with NULL argument
713 size_t lenUnicode = 2*lenAnsi;
714 #else
715 size_t lenUnicode = mbstowcs(NULL, help, lenAnsi);
716 #endif
717
718 // using the pointer of right type avoids us doing all sorts of
719 // pointer arithmetics ourselves
720 wchar_t *dst = (wchar_t *)ttText->szText,
721 *pwz = new wchar_t[lenUnicode + 1];
722 mbstowcs(pwz, help, lenAnsi + 1);
723 memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
724
725 // put the terminating _wide_ NUL
726 dst[lenUnicode] = 0;
727
728 delete [] pwz;
729 }
730 #endif // _WIN32_IE >= 0x0300
731 }
732
733 // For backward compatibility...
734 OnMouseEnter(tool->GetId());
735 */
736 return(TRUE);
737 }
738
739 // ----------------------------------------------------------------------------
740 // toolbar geometry
741 // ----------------------------------------------------------------------------
742
743 void wxToolBar::SetToolBitmapSize(
744 const wxSize& rSize
745 )
746 {
747 wxToolBarBase::SetToolBitmapSize(rSize);
748
749 // ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
750 }
751
752 void wxToolBar::SetRows(
753 int nRows
754 )
755 {
756 if (nRows == m_maxRows)
757 {
758 // avoid resizing the frame uselessly
759 return;
760 }
761 // TODO:
762 /*
763 // TRUE in wParam means to create at least as many rows, FALSE -
764 // at most as many
765 RECT rect;
766 ::SendMessage(GetHwnd(), TB_SETROWS,
767 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
768 (LPARAM) &rect);
769
770 m_maxRows = nRows;
771
772 UpdateSize();
773 */
774 }
775
776 // The button size is bigger than the bitmap size
777 wxSize wxToolBar::GetToolSize() const
778 {
779 // TODO:
780 /*
781 // TB_GETBUTTONSIZE is supported from version 4.70
782 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 )
783 if ( wxTheApp->GetComCtl32Version() >= 470 )
784 {
785 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
786
787 return wxSize(LOWORD(dw), HIWORD(dw));
788 }
789 else
790 #endif // comctl32.dll 4.70+
791 {
792 // defaults
793 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
794 }
795 */
796 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
797 }
798
799 wxToolBarToolBase *wxToolBar::FindToolForPosition(
800 wxCoord vX
801 , wxCoord vY
802 ) const
803 {
804 POINTL vPt;
805
806 vPt.x = vX;
807 vPt.y = vY;
808
809 int nIndex = 0; //(int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
810 if (nIndex < 0)
811 {
812 // it's a separator or there is no tool at all there
813 return (wxToolBarToolBase *)NULL;
814 }
815 return(m_tools.Item((size_t)nIndex)->GetData());
816 }
817
818 void wxToolBar::UpdateSize()
819 {
820 // we must refresh the frame after the toolbar size (possibly) changed
821 wxFrame* pFrame = wxDynamicCast(GetParent(), wxFrame);
822
823 if (pFrame)
824 {
825 // don't change the size, we just need to generate a WM_SIZE
826 RECTL vR;
827 // TODO:
828 /*
829 if ( !GetWindowRect(GetHwndOf(frame), &r) )
830 {
831 wxLogLastError(_T("GetWindowRect"));
832 }
833
834 (void)::SendMessage(GetHwndOf(frame), WM_SIZE, SIZE_RESTORED,
835 MAKELPARAM(r.right - r.left, r.bottom - r.top));
836 */
837 }
838 }
839
840 // ----------------------------------------------------------------------------
841 // tool state
842 // ----------------------------------------------------------------------------
843
844 void wxToolBar::DoEnableTool(
845 wxToolBarToolBase* pTool
846 , bool bEnable
847 )
848 {
849 // TODO:
850 /*
851 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
852 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
853 */
854 }
855
856 void wxToolBar::DoToggleTool(
857 wxToolBarToolBase* pTool
858 , bool bToggle
859 )
860 {
861 // TODO:
862 /*
863 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
864 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
865 */
866 }
867
868 void wxToolBar::DoSetToggle(
869 wxToolBarToolBase* pTool
870 , bool bToggle
871 )
872 {
873 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
874 // without, so we really need to delete the button and recreate it here
875 wxFAIL_MSG( _T("not implemented") );
876 }
877
878 // ----------------------------------------------------------------------------
879 // event handlers
880 // ----------------------------------------------------------------------------
881
882 // Responds to colour changes, and passes event on to children.
883 void wxToolBar::OnSysColourChanged(
884 wxSysColourChangedEvent& rEvent
885 )
886 {
887 // TODO:
888 /*
889 m_backgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
890 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
891 */
892
893 // Remap the buttons
894 Realize();
895
896 Refresh();
897
898 // Propagate the event to the non-top-level children
899 wxWindow::OnSysColourChanged(rEvent);
900 }
901
902 void wxToolBar::OnMouseEvent(
903 wxMouseEvent& rEvent
904 )
905 {
906 if (rEvent.RightDown())
907 {
908 // For now, we don't have an id. Later we could
909 // try finding the tool.
910 OnRightClick( (int)-1
911 ,rEvent.GetX()
912 ,rEvent.GetY()
913 );
914 }
915 else
916 {
917 rEvent.Skip();
918 }
919 }
920
921 MRESULT wxToolBar::OS2WindowProc(
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