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