]> git.saurik.com Git - wxWidgets.git/blob - src/msw/tbar95.cpp
use wxBusyCursor class instead of wxBeginBusyCursor and several (mismatched and thus...
[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
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
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 #include "wx/dcmemory.h"
39 #include "wx/control.h"
40 #endif
41
42 #if wxUSE_TOOLBAR && wxUSE_TOOLBAR_NATIVE && (!defined(_WIN32_WCE) || (_WIN32_WCE >= 400 && !wxUSE_POCKETPC_UI))
43
44 #include "wx/toolbar.h"
45
46 #include "wx/msw/private.h"
47
48 // include <commctrl.h> "properly"
49 #include "wx/msw/wrapcctl.h"
50
51 #include "wx/app.h" // for GetComCtl32Version
52
53 // ----------------------------------------------------------------------------
54 // conditional compilation
55 // ----------------------------------------------------------------------------
56
57 // wxWindows previously always considered that toolbar buttons have light grey
58 // (0xc0c0c0) background and so ignored any bitmap masks - however, this
59 // doesn't work with XPMs which then appear to have black background. To make
60 // this work, we must respect the bitmap masks - which we do now. This should
61 // be ok in any case, but to restore 100% compatible with the old version
62 // behaviour, you can set this to 0.
63 #define USE_BITMAP_MASKS 1
64
65 // ----------------------------------------------------------------------------
66 // constants
67 // ----------------------------------------------------------------------------
68
69 // these standard constants are not always defined in compilers headers
70
71 // Styles
72 #ifndef TBSTYLE_FLAT
73 #define TBSTYLE_LIST 0x1000
74 #define TBSTYLE_FLAT 0x0800
75 #endif
76
77 #ifndef TBSTYLE_TRANSPARENT
78 #define TBSTYLE_TRANSPARENT 0x8000
79 #endif
80
81 #ifndef TBSTYLE_TOOLTIPS
82 #define TBSTYLE_TOOLTIPS 0x0100
83 #endif
84
85 // Messages
86 #ifndef TB_GETSTYLE
87 #define TB_SETSTYLE (WM_USER + 56)
88 #define TB_GETSTYLE (WM_USER + 57)
89 #endif
90
91 #ifndef TB_HITTEST
92 #define TB_HITTEST (WM_USER + 69)
93 #endif
94
95 // these values correspond to those used by comctl32.dll
96 #define DEFAULTBITMAPX 16
97 #define DEFAULTBITMAPY 15
98 #define DEFAULTBUTTONX 24
99 #define DEFAULTBUTTONY 24
100 #define DEFAULTBARHEIGHT 27
101
102 // ----------------------------------------------------------------------------
103 // wxWin macros
104 // ----------------------------------------------------------------------------
105
106 IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxControl)
107
108 /*
109 TOOLBAR PROPERTIES
110 tool
111 bitmap
112 bitmap2
113 tooltip
114 longhelp
115 radio (bool)
116 toggle (bool)
117 separator
118 style ( wxNO_BORDER | wxTB_HORIZONTAL)
119 bitmapsize
120 margins
121 packing
122 separation
123
124 dontattachtoframe
125 */
126
127 BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
128 EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
129 EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
130 END_EVENT_TABLE()
131
132 // ----------------------------------------------------------------------------
133 // private classes
134 // ----------------------------------------------------------------------------
135
136 class wxToolBarTool : public wxToolBarToolBase
137 {
138 public:
139 wxToolBarTool(wxToolBar *tbar,
140 int id,
141 const wxString& label,
142 const wxBitmap& bmpNormal,
143 const wxBitmap& bmpDisabled,
144 wxItemKind kind,
145 wxObject *clientData,
146 const wxString& shortHelp,
147 const wxString& longHelp)
148 : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind,
149 clientData, shortHelp, longHelp)
150 {
151 m_nSepCount = 0;
152 }
153
154 wxToolBarTool(wxToolBar *tbar, wxControl *control)
155 : wxToolBarToolBase(tbar, control)
156 {
157 m_nSepCount = 1;
158 }
159
160 virtual void SetLabel(const wxString& label)
161 {
162 if ( label == m_label )
163 return;
164
165 wxToolBarToolBase::SetLabel(label);
166
167 // we need to update the label shown in the toolbar because it has a
168 // pointer to the internal buffer of the old label
169 //
170 // TODO: use TB_SETBUTTONINFO
171 }
172
173 // set/get the number of separators which we use to cover the space used by
174 // a control in the toolbar
175 void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
176 size_t GetSeparatorsCount() const { return m_nSepCount; }
177
178 private:
179 size_t m_nSepCount;
180
181 DECLARE_NO_COPY_CLASS(wxToolBarTool)
182 };
183
184
185 // ============================================================================
186 // implementation
187 // ============================================================================
188
189 // ----------------------------------------------------------------------------
190 // wxToolBarTool
191 // ----------------------------------------------------------------------------
192
193 wxToolBarToolBase *wxToolBar::CreateTool(int id,
194 const wxString& label,
195 const wxBitmap& bmpNormal,
196 const wxBitmap& bmpDisabled,
197 wxItemKind kind,
198 wxObject *clientData,
199 const wxString& shortHelp,
200 const wxString& longHelp)
201 {
202 return new wxToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind,
203 clientData, shortHelp, longHelp);
204 }
205
206 wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
207 {
208 return new wxToolBarTool(this, control);
209 }
210
211 // ----------------------------------------------------------------------------
212 // wxToolBar construction
213 // ----------------------------------------------------------------------------
214
215 void wxToolBar::Init()
216 {
217 m_hBitmap = 0;
218
219 m_nButtons = 0;
220
221 m_defaultWidth = DEFAULTBITMAPX;
222 m_defaultHeight = DEFAULTBITMAPY;
223
224 m_pInTool = 0;
225 }
226
227 bool wxToolBar::Create(wxWindow *parent,
228 wxWindowID id,
229 const wxPoint& pos,
230 const wxSize& size,
231 long style,
232 const wxString& name)
233 {
234 // common initialisation
235 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
236 return FALSE;
237
238 // MSW-specific initialisation
239 if ( !MSWCreateToolbar(pos, size) )
240 return FALSE;
241
242 // set up the colors and fonts
243 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR));
244 SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
245
246 return TRUE;
247 }
248
249 bool wxToolBar::MSWCreateToolbar(const wxPoint& pos, const wxSize& size)
250 {
251 if ( !MSWCreateControl(TOOLBARCLASSNAME, wxEmptyString, pos, size) )
252 return FALSE;
253
254 // toolbar-specific post initialisation
255 ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
256
257 return TRUE;
258 }
259
260 void wxToolBar::Recreate()
261 {
262 const HWND hwndOld = GetHwnd();
263 if ( !hwndOld )
264 {
265 // we haven't been created yet, no need to recreate
266 return;
267 }
268
269 // get the position and size before unsubclassing the old toolbar
270 const wxPoint pos = GetPosition();
271 const wxSize size = GetSize();
272
273 UnsubclassWin();
274
275 if ( !MSWCreateToolbar(pos, size) )
276 {
277 // what can we do?
278 wxFAIL_MSG( _T("recreating the toolbar failed") );
279
280 return;
281 }
282
283 // reparent all our children under the new toolbar
284 for ( wxWindowList::compatibility_iterator node = m_children.GetFirst();
285 node;
286 node = node->GetNext() )
287 {
288 wxWindow *win = node->GetData();
289 if ( !win->IsTopLevel() )
290 ::SetParent(GetHwndOf(win), GetHwnd());
291 }
292
293 // only destroy the old toolbar now -- after all the children had been
294 // reparented
295 ::DestroyWindow(hwndOld);
296
297 // it is for the old bitmap control and can't be used with the new one
298 if ( m_hBitmap )
299 {
300 ::DeleteObject((HBITMAP) m_hBitmap);
301 m_hBitmap = 0;
302 }
303
304 Realize();
305 UpdateSize();
306 }
307
308 wxToolBar::~wxToolBar()
309 {
310 // we must refresh the frame size when the toolbar is deleted but the frame
311 // is not - otherwise toolbar leaves a hole in the place it used to occupy
312 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
313 if ( frame && !frame->IsBeingDeleted() )
314 {
315 frame->SendSizeEvent();
316 }
317
318 if ( m_hBitmap )
319 {
320 ::DeleteObject((HBITMAP) m_hBitmap);
321 }
322 }
323
324 wxSize wxToolBar::DoGetBestSize() const
325 {
326 wxSize sizeBest = GetToolSize();
327 sizeBest.x *= GetToolsCount();
328
329 // reverse horz and vertical components if necessary
330 return HasFlag(wxTB_VERTICAL) ? wxSize(sizeBest.y, sizeBest.x) : sizeBest;
331 }
332
333 WXDWORD wxToolBar::MSWGetStyle(long style, WXDWORD *exstyle) const
334 {
335 // toolbars never have border, giving one to them results in broken
336 // appearance
337 WXDWORD msStyle = wxControl::MSWGetStyle
338 (
339 (style & ~wxBORDER_MASK) | wxBORDER_NONE, exstyle
340 );
341
342 // always include this one, it never hurts and setting it later only if we
343 // do have tooltips wouldn't work
344 msStyle |= TBSTYLE_TOOLTIPS;
345
346 if ( style & (wxTB_FLAT | wxTB_HORZ_LAYOUT) )
347 {
348 // static as it doesn't change during the program lifetime
349 static int s_verComCtl = wxTheApp->GetComCtl32Version();
350
351 // comctl32.dll 4.00 doesn't support the flat toolbars and using this
352 // style with 6.00 (part of Windows XP) leads to the toolbar with
353 // incorrect background colour - and not using it still results in the
354 // correct (flat) toolbar, so don't use it there
355 if ( s_verComCtl > 400 && s_verComCtl < 600 )
356 {
357 msStyle |= TBSTYLE_FLAT | TBSTYLE_TRANSPARENT;
358 }
359
360 if ( s_verComCtl >= 470 && style & wxTB_HORZ_LAYOUT )
361 {
362 msStyle |= TBSTYLE_LIST;
363 }
364 }
365
366 if ( style & wxTB_NODIVIDER )
367 msStyle |= CCS_NODIVIDER;
368
369 if ( style & wxTB_NOALIGN )
370 msStyle |= CCS_NOPARENTALIGN;
371
372 if ( style & wxTB_VERTICAL )
373 msStyle |= CCS_VERT;
374
375 return msStyle;
376 }
377
378 // ----------------------------------------------------------------------------
379 // adding/removing tools
380 // ----------------------------------------------------------------------------
381
382 bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos), wxToolBarToolBase *tool)
383 {
384 // nothing special to do here - we really create the toolbar buttons in
385 // Realize() later
386 tool->Attach(this);
387
388 return TRUE;
389 }
390
391 bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
392 {
393 // the main difficulty we have here is with the controls in the toolbars:
394 // as we (sometimes) use several separators to cover up the space used by
395 // them, the indices are not the same for us and the toolbar
396
397 // first determine the position of the first button to delete: it may be
398 // different from pos if we use several separators to cover the space used
399 // by a control
400 wxToolBarToolsList::compatibility_iterator node;
401 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
402 {
403 wxToolBarToolBase *tool2 = node->GetData();
404 if ( tool2 == tool )
405 {
406 // let node point to the next node in the list
407 node = node->GetNext();
408
409 break;
410 }
411
412 if ( tool2->IsControl() )
413 {
414 pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1;
415 }
416 }
417
418 // now determine the number of buttons to delete and the area taken by them
419 size_t nButtonsToDelete = 1;
420
421 // get the size of the button we're going to delete
422 RECT r;
423 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
424 {
425 wxLogLastError(_T("TB_GETITEMRECT"));
426 }
427
428 int width = r.right - r.left;
429
430 if ( tool->IsControl() )
431 {
432 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
433
434 width *= nButtonsToDelete;
435 }
436
437 // do delete all buttons
438 m_nButtons -= nButtonsToDelete;
439 while ( nButtonsToDelete-- > 0 )
440 {
441 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
442 {
443 wxLogLastError(wxT("TB_DELETEBUTTON"));
444
445 return FALSE;
446 }
447 }
448
449 tool->Detach();
450
451 // and finally reposition all the controls after this button (the toolbar
452 // takes care of all normal items)
453 for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
454 {
455 wxToolBarToolBase *tool2 = node->GetData();
456 if ( tool2->IsControl() )
457 {
458 int x;
459 wxControl *control = tool2->GetControl();
460 control->GetPosition(&x, NULL);
461 control->Move(x - width, -1);
462 }
463 }
464
465 return TRUE;
466 }
467
468 bool wxToolBar::Realize()
469 {
470 const size_t nTools = GetToolsCount();
471 if ( nTools == 0 )
472 {
473 // nothing to do
474 return TRUE;
475 }
476
477 const bool isVertical = HasFlag(wxTB_VERTICAL);
478
479 // delete all old buttons, if any
480 for ( size_t pos = 0; pos < m_nButtons; pos++ )
481 {
482 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
483 {
484 wxLogDebug(wxT("TB_DELETEBUTTON failed"));
485 }
486 }
487
488 // First, add the bitmap: we use one bitmap for all toolbar buttons
489 // ----------------------------------------------------------------
490
491 wxToolBarToolsList::compatibility_iterator node;
492 int bitmapId = 0;
493
494 wxSize sizeBmp;
495 if ( HasFlag(wxTB_NOICONS) )
496 {
497 // no icons, don't leave space for them
498 sizeBmp.x =
499 sizeBmp.y = 0;
500 }
501 else // do show icons
502 {
503 // if we already have a bitmap, we'll replace the existing one --
504 // otherwise we'll install a new one
505 HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
506
507 sizeBmp.x = m_defaultWidth;
508 sizeBmp.y = m_defaultHeight;
509
510 const wxCoord totalBitmapWidth = m_defaultWidth * nTools,
511 totalBitmapHeight = m_defaultHeight;
512
513 // Create a bitmap and copy all the tool bitmaps to it
514 #if USE_BITMAP_MASKS
515 wxMemoryDC dcAllButtons;
516 wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight);
517 dcAllButtons.SelectObject(bitmap);
518 dcAllButtons.SetBackground(*wxLIGHT_GREY_BRUSH);
519 dcAllButtons.Clear();
520
521 m_hBitmap = bitmap.GetHBITMAP();
522 HBITMAP hBitmap = (HBITMAP)m_hBitmap;
523 #else // !USE_BITMAP_MASKS
524 HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
525 totalBitmapWidth,
526 totalBitmapHeight);
527 if ( !hBitmap )
528 {
529 wxLogLastError(_T("CreateCompatibleBitmap"));
530
531 return FALSE;
532 }
533
534 m_hBitmap = (WXHBITMAP)hBitmap;
535
536 MemoryHDC memoryDC;
537 SelectInHDC hdcSelector(memoryDC, hBitmap);
538
539 MemoryHDC memoryDC2;
540 #endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
541
542 // the button position
543 wxCoord x = 0;
544
545 // the number of buttons (not separators)
546 int nButtons = 0;
547
548 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
549 {
550 wxToolBarToolBase *tool = node->GetData();
551 if ( tool->IsButton() )
552 {
553 const wxBitmap& bmp = tool->GetNormalBitmap();
554 if ( bmp.Ok() )
555 {
556 #if USE_BITMAP_MASKS
557 // notice the last parameter: do use mask
558 dcAllButtons.DrawBitmap(bmp, x, 0, TRUE);
559 #else // !USE_BITMAP_MASKS
560 SelectInHDC hdcSelector2(memoryDC2, GetHbitmapOf(bmp));
561 if ( !BitBlt(memoryDC,
562 x, 0, m_defaultWidth, m_defaultHeight,
563 memoryDC2,
564 0, 0, SRCCOPY) )
565 {
566 wxLogLastError(wxT("BitBlt"));
567 }
568 #endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
569 }
570 else
571 {
572 wxFAIL_MSG( _T("invalid tool button bitmap") );
573 }
574
575 // still inc width and number of buttons because otherwise the
576 // subsequent buttons will all be shifted which is rather confusing
577 // (and like this you'd see immediately which bitmap was bad)
578 x += m_defaultWidth;
579 nButtons++;
580 }
581 }
582
583 #if USE_BITMAP_MASKS
584 dcAllButtons.SelectObject(wxNullBitmap);
585
586 // don't delete this HBITMAP!
587 bitmap.SetHBITMAP(0);
588 #endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
589
590 // Map to system colours
591 hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
592 totalBitmapWidth, totalBitmapHeight);
593
594 bool addBitmap = TRUE;
595
596 if ( oldToolBarBitmap )
597 {
598 #ifdef TB_REPLACEBITMAP
599 if ( wxTheApp->GetComCtl32Version() >= 400 )
600 {
601 TBREPLACEBITMAP replaceBitmap;
602 replaceBitmap.hInstOld = NULL;
603 replaceBitmap.hInstNew = NULL;
604 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
605 replaceBitmap.nIDNew = (UINT) hBitmap;
606 replaceBitmap.nButtons = nButtons;
607 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
608 0, (LPARAM) &replaceBitmap) )
609 {
610 wxFAIL_MSG(wxT("Could not replace the old bitmap"));
611 }
612
613 ::DeleteObject(oldToolBarBitmap);
614
615 // already done
616 addBitmap = FALSE;
617 }
618 else
619 #endif // TB_REPLACEBITMAP
620 {
621 // we can't replace the old bitmap, so we will add another one
622 // (awfully inefficient, but what else to do?) and shift the bitmap
623 // indices accordingly
624 addBitmap = TRUE;
625
626 bitmapId = m_nButtons;
627 }
628 }
629
630 if ( addBitmap ) // no old bitmap or we can't replace it
631 {
632 TBADDBITMAP addBitmap;
633 addBitmap.hInst = 0;
634 addBitmap.nID = (UINT) hBitmap;
635 if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
636 (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
637 {
638 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
639 }
640 }
641 }
642
643 // don't call SetToolBitmapSize() as we don't want to change the values of
644 // m_defaultWidth/Height
645 if ( !::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0,
646 MAKELONG(sizeBmp.x, sizeBmp.y)) )
647 {
648 wxLogLastError(_T("TB_SETBITMAPSIZE"));
649 }
650
651 // Next add the buttons and separators
652 // -----------------------------------
653
654 TBBUTTON *buttons = new TBBUTTON[nTools];
655
656 // this array will hold the indices of all controls in the toolbar
657 wxArrayInt controlIds;
658
659 bool lastWasRadio = FALSE;
660 int i = 0;
661 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
662 {
663 wxToolBarToolBase *tool = node->GetData();
664
665 // don't add separators to the vertical toolbar with old comctl32.dll
666 // versions as they didn't handle this properly
667 if ( isVertical && tool->IsSeparator() &&
668 wxTheApp->GetComCtl32Version() <= 472 )
669 {
670 continue;
671 }
672
673
674 TBBUTTON& button = buttons[i];
675
676 wxZeroMemory(button);
677
678 bool isRadio = FALSE;
679 switch ( tool->GetStyle() )
680 {
681 case wxTOOL_STYLE_CONTROL:
682 button.idCommand = tool->GetId();
683 // fall through: create just a separator too
684
685 case wxTOOL_STYLE_SEPARATOR:
686 button.fsState = TBSTATE_ENABLED;
687 button.fsStyle = TBSTYLE_SEP;
688 break;
689
690 case wxTOOL_STYLE_BUTTON:
691 if ( !HasFlag(wxTB_NOICONS) )
692 button.iBitmap = bitmapId;
693
694 if ( HasFlag(wxTB_TEXT) )
695 {
696 const wxString& label = tool->GetLabel();
697 if ( !label.empty() )
698 {
699 button.iString = (int)label.c_str();
700 }
701 }
702
703 button.idCommand = tool->GetId();
704
705 if ( tool->IsEnabled() )
706 button.fsState |= TBSTATE_ENABLED;
707 if ( tool->IsToggled() )
708 button.fsState |= TBSTATE_CHECKED;
709
710 switch ( tool->GetKind() )
711 {
712 case wxITEM_RADIO:
713 button.fsStyle = TBSTYLE_CHECKGROUP;
714
715 if ( !lastWasRadio )
716 {
717 // the first item in the radio group is checked by
718 // default to be consistent with wxGTK and the menu
719 // radio items
720 button.fsState |= TBSTATE_CHECKED;
721
722 tool->Toggle(TRUE);
723 }
724
725 isRadio = TRUE;
726 break;
727
728 case wxITEM_CHECK:
729 button.fsStyle = TBSTYLE_CHECK;
730 break;
731
732 default:
733 wxFAIL_MSG( _T("unexpected toolbar button kind") );
734 // fall through
735
736 case wxITEM_NORMAL:
737 button.fsStyle = TBSTYLE_BUTTON;
738 }
739
740 bitmapId++;
741 break;
742 }
743
744 lastWasRadio = isRadio;
745
746 i++;
747 }
748
749 if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS, (WPARAM)i, (LPARAM)buttons) )
750 {
751 wxLogLastError(wxT("TB_ADDBUTTONS"));
752 }
753
754 delete [] buttons;
755
756 // Deal with the controls finally
757 // ------------------------------
758
759 // adjust the controls size to fit nicely in the toolbar
760 int y = 0;
761 size_t index = 0;
762 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
763 {
764 wxToolBarToolBase *tool = node->GetData();
765
766 // we calculate the running y coord for vertical toolbars so we need to
767 // get the items size for all items but for the horizontal ones we
768 // don't need to deal with the non controls
769 bool isControl = tool->IsControl();
770 if ( !isControl && !isVertical )
771 continue;
772
773 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
774 // latter only appeared in v4.70 of comctl32.dll
775 RECT r;
776 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
777 index, (LPARAM)(LPRECT)&r) )
778 {
779 wxLogLastError(wxT("TB_GETITEMRECT"));
780 }
781
782 if ( !isControl )
783 {
784 // can only be control if isVertical
785 y += r.bottom - r.top;
786
787 continue;
788 }
789
790 wxControl *control = tool->GetControl();
791
792 wxSize size = control->GetSize();
793
794 // the position of the leftmost controls corner
795 int left = -1;
796
797 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
798 #ifdef TB_SETBUTTONINFO
799 // available in headers, now check whether it is available now
800 // (during run-time)
801 if ( wxTheApp->GetComCtl32Version() >= 471 )
802 {
803 // set the (underlying) separators width to be that of the
804 // control
805 TBBUTTONINFO tbbi;
806 tbbi.cbSize = sizeof(tbbi);
807 tbbi.dwMask = TBIF_SIZE;
808 tbbi.cx = size.x;
809 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
810 tool->GetId(), (LPARAM)&tbbi) )
811 {
812 // the id is probably invalid?
813 wxLogLastError(wxT("TB_SETBUTTONINFO"));
814 }
815 }
816 else
817 #endif // comctl32.dll 4.71
818 // TB_SETBUTTONINFO unavailable
819 {
820 // try adding several separators to fit the controls width
821 int widthSep = r.right - r.left;
822 left = r.left;
823
824 TBBUTTON tbb;
825 wxZeroMemory(tbb);
826 tbb.idCommand = 0;
827 tbb.fsState = TBSTATE_ENABLED;
828 tbb.fsStyle = TBSTYLE_SEP;
829
830 size_t nSeparators = size.x / widthSep;
831 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
832 {
833 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
834 index, (LPARAM)&tbb) )
835 {
836 wxLogLastError(wxT("TB_INSERTBUTTON"));
837 }
838
839 index++;
840 }
841
842 // remember the number of separators we used - we'd have to
843 // delete all of them later
844 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
845
846 // adjust the controls width to exactly cover the separators
847 control->SetSize((nSeparators + 1)*widthSep, -1);
848 }
849
850 // position the control itself correctly vertically
851 int height = r.bottom - r.top;
852 int diff = height - size.y;
853 if ( diff < 0 )
854 {
855 // the control is too high, resize to fit
856 control->SetSize(-1, height - 2);
857
858 diff = 2;
859 }
860
861 int top;
862 if ( isVertical )
863 {
864 left = 0;
865 top = y;
866
867 y += height + 2*GetMargins().y;
868 }
869 else // horizontal toolbar
870 {
871 if ( left == -1 )
872 left = r.left;
873
874 top = r.top;
875 }
876
877 control->Move(left, top + (diff + 1) / 2);
878 }
879
880 // the max index is the "real" number of buttons - i.e. counting even the
881 // separators which we added just for aligning the controls
882 m_nButtons = index;
883
884 if ( !isVertical )
885 {
886 if ( m_maxRows == 0 )
887 {
888 // if not set yet, only one row
889 SetRows(1);
890 }
891 }
892 else if ( m_nButtons > 0 ) // vertical non empty toolbar
893 {
894 if ( m_maxRows == 0 )
895 {
896 // if not set yet, have one column
897 SetRows(m_nButtons);
898 }
899 }
900
901 return TRUE;
902 }
903
904 // ----------------------------------------------------------------------------
905 // message handlers
906 // ----------------------------------------------------------------------------
907
908 bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
909 {
910 wxToolBarToolBase *tool = FindById((int)id);
911 if ( !tool )
912 return FALSE;
913
914 bool toggled = false; // just to suppress warnings
915
916 if ( tool->CanBeToggled() )
917 {
918 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
919 toggled = (state & TBSTATE_CHECKED) != 0;
920
921 // ignore the event when a radio button is released, as this doesn't seem to
922 // happen at all, and is handled otherwise
923 if ( tool->GetKind() == wxITEM_RADIO && !toggled )
924 return TRUE;
925
926 tool->Toggle(toggled);
927 UnToggleRadioGroup(tool);
928 }
929
930 // OnLeftClick() can veto the button state change - for buttons which
931 // may be toggled only, of couse
932 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
933 {
934 // revert back
935 tool->Toggle(!toggled);
936
937 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
938 }
939
940 return TRUE;
941 }
942
943 bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
944 WXLPARAM lParam,
945 WXLPARAM *WXUNUSED(result))
946 {
947 #if wxUSE_TOOLTIPS
948 // First check if this applies to us
949 NMHDR *hdr = (NMHDR *)lParam;
950
951 // the tooltips control created by the toolbar is sometimes Unicode, even
952 // in an ANSI application - this seems to be a bug in comctl32.dll v5
953 UINT code = hdr->code;
954 if ( (code != (UINT) TTN_NEEDTEXTA) && (code != (UINT) TTN_NEEDTEXTW) )
955 return FALSE;
956
957 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
958 if ( toolTipWnd != hdr->hwndFrom )
959 return FALSE;
960
961 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
962 int id = (int)ttText->hdr.idFrom;
963
964 wxToolBarToolBase *tool = FindById(id);
965 if ( !tool )
966 return FALSE;
967
968 return HandleTooltipNotify(code, lParam, tool->GetShortHelp());
969 #else
970 return FALSE;
971 #endif
972 }
973
974 // ----------------------------------------------------------------------------
975 // toolbar geometry
976 // ----------------------------------------------------------------------------
977
978 void wxToolBar::SetToolBitmapSize(const wxSize& size)
979 {
980 wxToolBarBase::SetToolBitmapSize(size);
981
982 ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
983 }
984
985 void wxToolBar::SetRows(int nRows)
986 {
987 if ( nRows == m_maxRows )
988 {
989 // avoid resizing the frame uselessly
990 return;
991 }
992
993 // TRUE in wParam means to create at least as many rows, FALSE -
994 // at most as many
995 RECT rect;
996 ::SendMessage(GetHwnd(), TB_SETROWS,
997 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
998 (LPARAM) &rect);
999
1000 m_maxRows = nRows;
1001
1002 UpdateSize();
1003 }
1004
1005 // The button size is bigger than the bitmap size
1006 wxSize wxToolBar::GetToolSize() const
1007 {
1008 // TB_GETBUTTONSIZE is supported from version 4.70
1009 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \
1010 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) ) \
1011 && !defined (__DIGITALMARS__)
1012 if ( wxTheApp->GetComCtl32Version() >= 470 )
1013 {
1014 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
1015
1016 return wxSize(LOWORD(dw), HIWORD(dw));
1017 }
1018 else
1019 #endif // comctl32.dll 4.70+
1020 {
1021 // defaults
1022 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
1023 }
1024 }
1025
1026 static
1027 wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
1028 size_t index )
1029 {
1030 wxToolBarToolsList::compatibility_iterator current = tools.GetFirst();
1031
1032 for ( ; current != 0; current = current->GetNext() )
1033 {
1034 if ( index == 0 )
1035 return current->GetData();
1036
1037 wxToolBarTool *tool = (wxToolBarTool *)current->GetData();
1038 size_t separators = tool->GetSeparatorsCount();
1039
1040 // if it is a normal button, sepcount == 0, so skip 1 item (the button)
1041 // otherwise, skip as many items as the separator count, plus the
1042 // control itself
1043 index -= separators ? separators + 1 : 1;
1044 }
1045
1046 return 0;
1047 }
1048
1049 wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
1050 {
1051 POINT pt;
1052 pt.x = x;
1053 pt.y = y;
1054 int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
1055 // MBN: when the point ( x, y ) is close to the toolbar border
1056 // TB_HITTEST returns m_nButtons ( not -1 )
1057 if ( index < 0 || (size_t)index >= m_nButtons )
1058 {
1059 // it's a separator or there is no tool at all there
1060 return (wxToolBarToolBase *)NULL;
1061 }
1062
1063 // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers
1064 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
1065 if ( wxTheApp->GetComCtl32Version() >= 471 )
1066 {
1067 return m_tools.Item((size_t)index)->GetData();
1068 }
1069 else
1070 #endif
1071 {
1072 return GetItemSkippingDummySpacers( m_tools, (size_t) index );
1073 }
1074 }
1075
1076 void wxToolBar::UpdateSize()
1077 {
1078 // the toolbar size changed
1079 SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0);
1080
1081 // we must also refresh the frame after the toolbar size (possibly) changed
1082 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
1083 if ( frame )
1084 {
1085 frame->SendSizeEvent();
1086 }
1087 }
1088
1089 // ----------------------------------------------------------------------------
1090 // toolbar styles
1091 // ---------------------------------------------------------------------------
1092
1093 void wxToolBar::SetWindowStyleFlag(long style)
1094 {
1095 // the style bits whose changes force us to recreate the toolbar
1096 static const long MASK_NEEDS_RECREATE = wxTB_TEXT | wxTB_NOICONS;
1097
1098 const long styleOld = GetWindowStyle();
1099
1100 wxToolBarBase::SetWindowStyleFlag(style);
1101
1102 // don't recreate an empty toolbar: not only this is unnecessary, but it is
1103 // also fatal as we'd then try to recreate the toolbar when it's just being
1104 // created
1105 if ( GetToolsCount() &&
1106 (style & MASK_NEEDS_RECREATE) != (styleOld & MASK_NEEDS_RECREATE) )
1107 {
1108 // to remove the text labels, simply re-realizing the toolbar is enough
1109 // but I don't know of any way to add the text to an existing toolbar
1110 // other than by recreating it entirely
1111 Recreate();
1112 }
1113 }
1114
1115 // ----------------------------------------------------------------------------
1116 // tool state
1117 // ----------------------------------------------------------------------------
1118
1119 void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
1120 {
1121 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
1122 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
1123 }
1124
1125 void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
1126 {
1127 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
1128 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
1129 }
1130
1131 void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
1132 {
1133 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
1134 // without, so we really need to delete the button and recreate it here
1135 wxFAIL_MSG( _T("not implemented") );
1136 }
1137
1138 // ----------------------------------------------------------------------------
1139 // event handlers
1140 // ----------------------------------------------------------------------------
1141
1142 // Responds to colour changes, and passes event on to children.
1143 void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
1144 {
1145 wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));
1146
1147 // Remap the buttons
1148 Realize();
1149
1150 // Relayout the toolbar
1151 int nrows = m_maxRows;
1152 m_maxRows = 0; // otherwise SetRows() wouldn't do anything
1153 SetRows(nrows);
1154
1155 Refresh();
1156
1157 // let the event propagate further
1158 event.Skip();
1159 }
1160
1161 void wxToolBar::OnMouseEvent(wxMouseEvent& event)
1162 {
1163 if (event.Leaving() && m_pInTool)
1164 {
1165 OnMouseEnter( -1 );
1166 event.Skip();
1167 return;
1168 }
1169
1170 if (event.RightDown())
1171 {
1172 // For now, we don't have an id. Later we could
1173 // try finding the tool.
1174 OnRightClick((int)-1, event.GetX(), event.GetY());
1175 }
1176 else
1177 {
1178 event.Skip();
1179 }
1180 }
1181
1182 bool wxToolBar::HandleSize(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
1183 {
1184 // calculate our minor dimension ourselves - we're confusing the standard
1185 // logic (TB_AUTOSIZE) with our horizontal toolbars and other hacks
1186 RECT r;
1187 if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) )
1188 {
1189 int w, h;
1190
1191 if ( GetWindowStyle() & wxTB_VERTICAL )
1192 {
1193 w = r.right - r.left;
1194 if ( m_maxRows )
1195 {
1196 w *= (m_nButtons + m_maxRows - 1)/m_maxRows;
1197 }
1198 h = HIWORD(lParam);
1199 }
1200 else
1201 {
1202 w = LOWORD(lParam);
1203 if (HasFlag( wxTB_FLAT ))
1204 h = r.bottom - r.top - 3;
1205 else
1206 h = r.bottom - r.top;
1207 if ( m_maxRows )
1208 {
1209 // FIXME: hardcoded separator line height...
1210 h += HasFlag(wxTB_NODIVIDER) ? 4 : 6;
1211 h *= m_maxRows;
1212 }
1213 }
1214
1215 if ( MAKELPARAM(w, h) != lParam )
1216 {
1217 // size really changed
1218 SetSize(w, h);
1219 }
1220
1221 // message processed
1222 return TRUE;
1223 }
1224
1225 return FALSE;
1226 }
1227
1228 bool wxToolBar::HandlePaint(WXWPARAM wParam, WXLPARAM lParam)
1229 {
1230 // erase any dummy separators which we used for aligning the controls if
1231 // any here
1232
1233 // first of all, do we have any controls at all?
1234 wxToolBarToolsList::compatibility_iterator node;
1235 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
1236 {
1237 if ( node->GetData()->IsControl() )
1238 break;
1239 }
1240
1241 if ( !node )
1242 {
1243 // no controls, nothing to erase
1244 return FALSE;
1245 }
1246
1247 // prepare the DC on which we'll be drawing
1248 wxClientDC dc(this);
1249 dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
1250 dc.SetPen(*wxTRANSPARENT_PEN);
1251
1252 RECT r;
1253 if ( !GetUpdateRect(GetHwnd(), &r, FALSE) )
1254 {
1255 // nothing to redraw anyhow
1256 return FALSE;
1257 }
1258
1259 wxRect rectUpdate;
1260 wxCopyRECTToRect(r, rectUpdate);
1261
1262 dc.SetClippingRegion(rectUpdate);
1263
1264 // draw the toolbar tools, separators &c normally
1265 wxControl::MSWWindowProc(WM_PAINT, wParam, lParam);
1266
1267 // for each control in the toolbar find all the separators intersecting it
1268 // and erase them
1269 //
1270 // NB: this is really the only way to do it as we don't know if a separator
1271 // corresponds to a control (i.e. is a dummy one) or a real one
1272 // otherwise
1273 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
1274 {
1275 wxToolBarToolBase *tool = node->GetData();
1276 if ( tool->IsControl() )
1277 {
1278 // get the control rect in our client coords
1279 wxControl *control = tool->GetControl();
1280 wxRect rectCtrl = control->GetRect();
1281
1282 // iterate over all buttons
1283 TBBUTTON tbb;
1284 int count = ::SendMessage(GetHwnd(), TB_BUTTONCOUNT, 0, 0);
1285 for ( int n = 0; n < count; n++ )
1286 {
1287 // is it a separator?
1288 if ( !::SendMessage(GetHwnd(), TB_GETBUTTON,
1289 n, (LPARAM)&tbb) )
1290 {
1291 wxLogDebug(_T("TB_GETBUTTON failed?"));
1292
1293 continue;
1294 }
1295
1296 if ( tbb.fsStyle != TBSTYLE_SEP )
1297 continue;
1298
1299 // get the bounding rect of the separator
1300 RECT r;
1301 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT,
1302 n, (LPARAM)&r) )
1303 {
1304 wxLogDebug(_T("TB_GETITEMRECT failed?"));
1305
1306 continue;
1307 }
1308
1309 // does it intersect the control?
1310 wxRect rectItem;
1311 wxCopyRECTToRect(r, rectItem);
1312 if ( rectCtrl.Intersects(rectItem) )
1313 {
1314 // yes, do erase it!
1315 dc.DrawRectangle(rectItem);
1316
1317 // Necessary in case we use a no-paint-on-size
1318 // style in the parent: the controls can disappear
1319 control->Refresh(FALSE);
1320 }
1321 }
1322 }
1323 }
1324
1325 return TRUE;
1326 }
1327
1328 void wxToolBar::HandleMouseMove(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
1329 {
1330 wxCoord x = GET_X_LPARAM(lParam),
1331 y = GET_Y_LPARAM(lParam);
1332 wxToolBarToolBase* tool = FindToolForPosition( x, y );
1333
1334 // cursor left current tool
1335 if( tool != m_pInTool && !tool )
1336 {
1337 m_pInTool = 0;
1338 OnMouseEnter( -1 );
1339 }
1340
1341 // cursor entered a tool
1342 if( tool != m_pInTool && tool )
1343 {
1344 m_pInTool = tool;
1345 OnMouseEnter( tool->GetId() );
1346 }
1347 }
1348
1349 long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
1350 {
1351 switch ( nMsg )
1352 {
1353 case WM_SIZE:
1354 if ( HandleSize(wParam, lParam) )
1355 return 0;
1356 break;
1357
1358 case WM_MOUSEMOVE:
1359 // we don't handle mouse moves, so always pass the message to
1360 // wxControl::MSWWindowProc
1361 HandleMouseMove(wParam, lParam);
1362 break;
1363
1364 case WM_PAINT:
1365 if ( HandlePaint(wParam, lParam) )
1366 return 0;
1367 }
1368
1369 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
1370 }
1371
1372 // ----------------------------------------------------------------------------
1373 // private functions
1374 // ----------------------------------------------------------------------------
1375
1376 WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height)
1377 {
1378 MemoryHDC hdcMem;
1379
1380 if ( !hdcMem )
1381 {
1382 wxLogLastError(_T("CreateCompatibleDC"));
1383
1384 return bitmap;
1385 }
1386
1387 SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap);
1388
1389 if ( !bmpInHDC )
1390 {
1391 wxLogLastError(_T("SelectObject"));
1392
1393 return bitmap;
1394 }
1395
1396 wxCOLORMAP *cmap = wxGetStdColourMap();
1397
1398 for ( int i = 0; i < width; i++ )
1399 {
1400 for ( int j = 0; j < height; j++ )
1401 {
1402 COLORREF pixel = ::GetPixel(hdcMem, i, j);
1403
1404 for ( size_t k = 0; k < wxSTD_COL_MAX; k++ )
1405 {
1406 COLORREF col = cmap[k].from;
1407 if ( abs(GetRValue(pixel) - GetRValue(col)) < 10 &&
1408 abs(GetGValue(pixel) - GetGValue(col)) < 10 &&
1409 abs(GetBValue(pixel) - GetBValue(col)) < 10 )
1410 {
1411 ::SetPixel(hdcMem, i, j, cmap[k].to);
1412 break;
1413 }
1414 }
1415 }
1416 }
1417
1418 return bitmap;
1419
1420 // VZ: I leave here my attempts to map the bitmap to the system colours
1421 // faster by using BitBlt() even though it's broken currently - but
1422 // maybe someone else can finish it? It should be faster than iterating
1423 // over all pixels...
1424 #if 0
1425 MemoryHDC hdcMask, hdcDst;
1426 if ( !hdcMask || !hdcDst )
1427 {
1428 wxLogLastError(_T("CreateCompatibleDC"));
1429
1430 return bitmap;
1431 }
1432
1433 // create the target bitmap
1434 HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height);
1435 if ( !hbmpDst )
1436 {
1437 wxLogLastError(_T("CreateCompatibleBitmap"));
1438
1439 return bitmap;
1440 }
1441
1442 // create the monochrome mask bitmap
1443 HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0);
1444 if ( !hbmpMask )
1445 {
1446 wxLogLastError(_T("CreateBitmap(mono)"));
1447
1448 ::DeleteObject(hbmpDst);
1449
1450 return bitmap;
1451 }
1452
1453 SelectInHDC bmpInDst(hdcDst, hbmpDst),
1454 bmpInMask(hdcMask, hbmpMask);
1455
1456 // for each colour:
1457 for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ )
1458 {
1459 // create the mask for this colour
1460 ::SetBkColor(hdcMem, ColorMap[n].from);
1461 ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
1462
1463 // replace this colour with the target one in the dst bitmap
1464 HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to);
1465 HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr);
1466
1467 ::MaskBlt(hdcDst, 0, 0, width, height,
1468 hdcMem, 0, 0,
1469 hbmpMask, 0, 0,
1470 MAKEROP4(PATCOPY, SRCCOPY));
1471
1472 (void)::SelectObject(hdcDst, hbrOld);
1473 ::DeleteObject(hbr);
1474 }
1475
1476 ::DeleteObject((HBITMAP)bitmap);
1477
1478 return (WXHBITMAP)hbmpDst;
1479 #endif // 0
1480 }
1481
1482 #endif // wxUSE_TOOLBAR && Win95
1483