]> git.saurik.com Git - wxWidgets.git/blame - src/msw/tbar95.cpp
PyCrust updates
[wxWidgets.git] / src / msw / tbar95.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
1c383dba 2// Name: msw/tbar95.cpp
8a0681f9 3// Purpose: wxToolBar
2bda0e17
KB
4// Author: Julian Smart
5// Modified by:
6// Created: 04/01/98
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart and Markus Holzem
89b892a2 9// Licence: wxWindows license
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
1c383dba
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17 20#ifdef __GNUG__
1c383dba 21 #pragma implementation "tbar95.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
1c383dba 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
8a0681f9 32 #include "wx/frame.h"
1c383dba
VZ
33 #include "wx/log.h"
34 #include "wx/intl.h"
35 #include "wx/dynarray.h"
4e15f6c5 36 #include "wx/settings.h"
381dd4bf 37 #include "wx/bitmap.h"
f6bcfd97 38 #include "wx/dcmemory.h"
2bda0e17
KB
39#endif
40
8a0681f9
VZ
41#if wxUSE_TOOLBAR && defined(__WIN95__) && wxUSE_TOOLBAR_NATIVE
42
43#include "wx/toolbar.h"
2bda0e17 44
ce3ed50d 45#if !defined(__GNUWIN32__) && !defined(__SALFORDC__)
1c383dba 46 #include "malloc.h"
2bda0e17
KB
47#endif
48
1c383dba 49#include "wx/msw/private.h"
2bda0e17 50
57c208c5 51#ifndef __TWIN32__
1c383dba 52
ae090fdb 53#if defined(__WIN95__) && !((defined(__GNUWIN32_OLD__) || defined(__TWIN32__)) && !defined(__CYGWIN10__))
1c383dba 54 #include <commctrl.h>
ae090fdb
JS
55#else
56 #include "wx/msw/gnuwin32/extra.h"
65fd5cb0 57#endif
2bda0e17 58
1c383dba
VZ
59#endif // __TWIN32__
60
2bda0e17 61#include "wx/msw/dib.h"
1c383dba
VZ
62#include "wx/app.h" // for GetComCtl32Version
63
de85a884
VZ
64#if defined(__MWERKS__) && defined(__WXMSW__)
65// including <windef.h> for max definition doesn't seem
66// to work using CodeWarrior 6 Windows. So we define it
67// here. (Otherwise we get a undefined identifier 'max'
68// later on in this file.) (Added by dimitri@shortcut.nl)
69# ifndef max
70# define max(a,b) (((a) > (b)) ? (a) : (b))
71# endif
72
73#endif
74
f6bcfd97
BP
75// ----------------------------------------------------------------------------
76// conditional compilation
77// ----------------------------------------------------------------------------
78
79// wxWindows previously always considered that toolbar buttons have light grey
80// (0xc0c0c0) background and so ignored any bitmap masks - however, this
81// doesn't work with XPMs which then appear to have black background. To make
82// this work, we must respect the bitmap masks - which we do now. This should
83// be ok in any case, but to restore 100% compatible with the old version
84// behaviour, you can set this to 0.
85#define USE_BITMAP_MASKS 1
86
1c383dba
VZ
87// ----------------------------------------------------------------------------
88// constants
89// ----------------------------------------------------------------------------
90
91// these standard constants are not always defined in compilers headers
2bda0e17 92
6a23cbce 93// Styles
bb6290e3 94#ifndef TBSTYLE_FLAT
1c383dba
VZ
95 #define TBSTYLE_LIST 0x1000
96 #define TBSTYLE_FLAT 0x0800
97 #define TBSTYLE_TRANSPARENT 0x8000
bb6290e3
JS
98#endif
99 // use TBSTYLE_TRANSPARENT if you use TBSTYLE_FLAT
100
6a23cbce
JS
101// Messages
102#ifndef TB_GETSTYLE
1c383dba 103 #define TB_SETSTYLE (WM_USER + 56)
8a0681f9
VZ
104 #define TB_GETSTYLE (WM_USER + 57)
105#endif
106
107#ifndef TB_HITTEST
108 #define TB_HITTEST (WM_USER + 69)
6a23cbce
JS
109#endif
110
1c383dba 111// these values correspond to those used by comctl32.dll
81d66cf3
JS
112#define DEFAULTBITMAPX 16
113#define DEFAULTBITMAPY 15
114#define DEFAULTBUTTONX 24
115#define DEFAULTBUTTONY 24
116#define DEFAULTBARHEIGHT 27
117
1c383dba
VZ
118// ----------------------------------------------------------------------------
119// wxWin macros
120// ----------------------------------------------------------------------------
121
12ed316d 122IMPLEMENT_DYNAMIC_CLASS(wxToolBar, wxToolBarBase)
2bda0e17 123
8a0681f9
VZ
124BEGIN_EVENT_TABLE(wxToolBar, wxToolBarBase)
125 EVT_MOUSE_EVENTS(wxToolBar::OnMouseEvent)
126 EVT_SYS_COLOUR_CHANGED(wxToolBar::OnSysColourChanged)
2bda0e17 127END_EVENT_TABLE()
2bda0e17 128
8a0681f9
VZ
129// ----------------------------------------------------------------------------
130// private classes
131// ----------------------------------------------------------------------------
132
133class wxToolBarTool : public wxToolBarToolBase
134{
135public:
136 wxToolBarTool(wxToolBar *tbar,
137 int id,
138 const wxBitmap& bitmap1,
139 const wxBitmap& bitmap2,
140 bool toggle,
141 wxObject *clientData,
142 const wxString& shortHelpString,
143 const wxString& longHelpString)
144 : wxToolBarToolBase(tbar, id, bitmap1, bitmap2, toggle,
145 clientData, shortHelpString, longHelpString)
146 {
147 m_nSepCount = 0;
148 }
149
150 wxToolBarTool(wxToolBar *tbar, wxControl *control)
151 : wxToolBarToolBase(tbar, control)
152 {
153 m_nSepCount = 1;
154 }
155
156 // set/get the number of separators which we use to cover the space used by
157 // a control in the toolbar
158 void SetSeparatorsCount(size_t count) { m_nSepCount = count; }
159 size_t GetSeparatorsCount() const { return m_nSepCount; }
160
161private:
162 size_t m_nSepCount;
163};
164
165
1c383dba
VZ
166// ============================================================================
167// implementation
168// ============================================================================
2bda0e17 169
1c383dba 170// ----------------------------------------------------------------------------
8a0681f9 171// wxToolBarTool
1c383dba
VZ
172// ----------------------------------------------------------------------------
173
8a0681f9
VZ
174wxToolBarToolBase *wxToolBar::CreateTool(int id,
175 const wxBitmap& bitmap1,
176 const wxBitmap& bitmap2,
177 bool toggle,
178 wxObject *clientData,
179 const wxString& shortHelpString,
180 const wxString& longHelpString)
181{
182 return new wxToolBarTool(this, id, bitmap1, bitmap2, toggle,
183 clientData, shortHelpString, longHelpString);
184}
185
186wxToolBarToolBase *wxToolBar::CreateTool(wxControl *control)
187{
188 return new wxToolBarTool(this, control);
189}
190
191// ----------------------------------------------------------------------------
192// wxToolBar construction
193// ----------------------------------------------------------------------------
194
195void wxToolBar::Init()
2bda0e17 196{
1c383dba 197 m_hBitmap = 0;
8a0681f9
VZ
198
199 m_nButtons = 0;
200
1c383dba
VZ
201 m_defaultWidth = DEFAULTBITMAPX;
202 m_defaultHeight = DEFAULTBITMAPY;
37d0bdff
MB
203
204 m_pInTool = 0;
2bda0e17
KB
205}
206
8a0681f9
VZ
207bool wxToolBar::Create(wxWindow *parent,
208 wxWindowID id,
209 const wxPoint& pos,
210 const wxSize& size,
211 long style,
212 const wxString& name)
2bda0e17 213{
a4aad4de
VZ
214 // toolbars never have border, giving one to them results in broken
215 // appearance
216 style &= ~wxBORDER_MASK;
217 style |= wxBORDER_NONE;
218
1c383dba 219 // common initialisation
11b6a93b 220 if ( !CreateControl(parent, id, pos, size, style, wxDefaultValidator, name) )
1c383dba 221 return FALSE;
89b892a2 222
1c383dba
VZ
223 // prepare flags
224 DWORD msflags = 0; // WS_VISIBLE | WS_CHILD always included
c25a510b 225
b0766406
JS
226 if ( style & wxCLIP_SIBLINGS )
227 msflags |= WS_CLIPSIBLINGS;
228
c25a510b 229#ifdef TBSTYLE_TOOLTIPS
1c383dba 230 msflags |= TBSTYLE_TOOLTIPS;
c25a510b 231#endif
2bda0e17 232
1c383dba
VZ
233 if (style & wxTB_FLAT)
234 {
235 if (wxTheApp->GetComCtl32Version() > 400)
c8f1f088 236 msflags |= TBSTYLE_FLAT;
1c383dba 237 }
2bda0e17 238
1c383dba
VZ
239 // MSW-specific initialisation
240 if ( !wxControl::MSWCreateControl(TOOLBARCLASSNAME, msflags) )
241 return FALSE;
2bda0e17 242
c8f1f088 243 // toolbar-specific post initialisation
1c383dba 244 ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
89b892a2 245
c8f1f088
VZ
246 // set up the colors and fonts
247 wxRGBToColour(m_backgroundColour, GetSysColor(COLOR_BTNFACE));
248 m_foregroundColour = *wxBLACK;
249
250 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
251
1c383dba
VZ
252 // position it
253 int x = pos.x;
254 int y = pos.y;
255 int width = size.x;
256 int height = size.y;
2bda0e17 257
1c383dba
VZ
258 if (width <= 0)
259 width = 100;
260 if (height <= 0)
261 height = m_defaultHeight;
262 if (x < 0)
263 x = 0;
264 if (y < 0)
265 y = 0;
bb6290e3 266
1c383dba 267 SetSize(x, y, width, height);
2bda0e17 268
1c383dba 269 return TRUE;
2bda0e17
KB
270}
271
8a0681f9 272wxToolBar::~wxToolBar()
2bda0e17 273{
f6bcfd97
BP
274 // we must refresh the frame size when the toolbar is deleted but the frame
275 // is not - otherwise toolbar leaves a hole in the place it used to occupy
f6bcfd97 276 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
c2fd78b1 277 if ( frame && !frame->IsBeingDeleted() )
f6bcfd97
BP
278 {
279 frame->SendSizeEvent();
280 }
281
282 if ( m_hBitmap )
1c383dba
VZ
283 {
284 ::DeleteObject((HBITMAP) m_hBitmap);
285 }
286}
287
bdc72a22 288// ----------------------------------------------------------------------------
8a0681f9 289// adding/removing tools
bdc72a22
VZ
290// ----------------------------------------------------------------------------
291
8a0681f9
VZ
292bool wxToolBar::DoInsertTool(size_t WXUNUSED(pos),
293 wxToolBarToolBase *tool)
1c383dba 294{
8a0681f9
VZ
295 // nothing special to do here - we really create the toolbar buttons in
296 // Realize() later
297 tool->Attach(this);
298
299 return TRUE;
1c383dba
VZ
300}
301
8a0681f9 302bool wxToolBar::DoDeleteTool(size_t pos, wxToolBarToolBase *tool)
bdc72a22 303{
f6bcfd97
BP
304 // the main difficulty we have here is with the controls in the toolbars:
305 // as we (sometimes) use several separators to cover up the space used by
306 // them, the indices are not the same for us and the toolbar
307
308 // first determine the position of the first button to delete: it may be
309 // different from pos if we use several separators to cover the space used
310 // by a control
311 wxToolBarToolsList::Node *node;
312 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
313 {
314 wxToolBarToolBase *tool2 = node->GetData();
315 if ( tool2 == tool )
316 {
317 // let node point to the next node in the list
318 node = node->GetNext();
319
320 break;
321 }
322
323 if ( tool2->IsControl() )
324 {
56bd6aac 325 pos += ((wxToolBarTool *)tool2)->GetSeparatorsCount() - 1;
f6bcfd97
BP
326 }
327 }
328
329 // now determine the number of buttons to delete and the area taken by them
8a0681f9 330 size_t nButtonsToDelete = 1;
bdc72a22 331
8a0681f9
VZ
332 // get the size of the button we're going to delete
333 RECT r;
334 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
bdc72a22 335 {
8a0681f9 336 wxLogLastError(_T("TB_GETITEMRECT"));
bdc72a22
VZ
337 }
338
8a0681f9 339 int width = r.right - r.left;
bdc72a22 340
8a0681f9
VZ
341 if ( tool->IsControl() )
342 {
343 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
bdc72a22 344
8a0681f9
VZ
345 width *= nButtonsToDelete;
346 }
bdc72a22 347
f6bcfd97
BP
348 // do delete all buttons
349 m_nButtons -= nButtonsToDelete;
8a0681f9
VZ
350 while ( nButtonsToDelete-- > 0 )
351 {
352 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
353 {
f6bcfd97 354 wxLogLastError(wxT("TB_DELETEBUTTON"));
1c383dba 355
8a0681f9
VZ
356 return FALSE;
357 }
358 }
1c383dba 359
8a0681f9 360 tool->Detach();
1c383dba 361
f6bcfd97
BP
362 // and finally reposition all the controls after this button (the toolbar
363 // takes care of all normal items)
364 for ( /* node -> first after deleted */ ; node; node = node->GetNext() )
8a0681f9
VZ
365 {
366 wxToolBarToolBase *tool2 = node->GetData();
367 if ( tool2->IsControl() )
368 {
369 int x;
370 wxControl *control = tool2->GetControl();
371 control->GetPosition(&x, NULL);
372 control->Move(x - width, -1);
373 }
374 }
1c383dba
VZ
375
376 return TRUE;
377}
378
8a0681f9 379bool wxToolBar::Realize()
1c383dba 380{
8a0681f9
VZ
381 size_t nTools = GetToolsCount();
382 if ( nTools == 0 )
383 {
384 // nothing to do
385 return TRUE;
386 }
1c383dba 387
8a0681f9 388 bool isVertical = (GetWindowStyle() & wxTB_VERTICAL) != 0;
2bda0e17 389
8a0681f9
VZ
390 // First, add the bitmap: we use one bitmap for all toolbar buttons
391 // ----------------------------------------------------------------
2bda0e17 392
8a0681f9
VZ
393 // if we already have a bitmap, we'll replace the existing one - otherwise
394 // we'll install a new one
395 HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
89b892a2 396
1c383dba
VZ
397 int totalBitmapWidth = (int)(m_defaultWidth * nTools);
398 int totalBitmapHeight = (int)m_defaultHeight;
2bda0e17 399
f6bcfd97
BP
400 // Create a bitmap and copy all the tool bitmaps to it
401#if USE_BITMAP_MASKS
402 wxMemoryDC dcAllButtons;
403 wxBitmap bitmap(totalBitmapWidth, totalBitmapHeight);
404 dcAllButtons.SelectObject(bitmap);
405 dcAllButtons.SetBackground(*wxLIGHT_GREY_BRUSH);
406 dcAllButtons.Clear();
407
408 m_hBitmap = bitmap.GetHBITMAP();
409 HBITMAP hBitmap = (HBITMAP)m_hBitmap;
410#else // !USE_BITMAP_MASKS
8a0681f9
VZ
411 HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
412 totalBitmapWidth,
413 totalBitmapHeight);
414 if ( !hBitmap )
415 {
416 wxLogLastError(_T("CreateCompatibleBitmap"));
417
418 return FALSE;
419 }
420
421 m_hBitmap = (WXHBITMAP)hBitmap;
89b892a2 422
1c383dba 423 HDC memoryDC = ::CreateCompatibleDC(NULL);
8a0681f9 424 HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, hBitmap);
2bda0e17 425
1c383dba 426 HDC memoryDC2 = ::CreateCompatibleDC(NULL);
f6bcfd97 427#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
2bda0e17 428
1c383dba
VZ
429 // the button position
430 wxCoord x = 0;
2bda0e17 431
1c383dba 432 // the number of buttons (not separators)
8a0681f9 433 int nButtons = 0;
1c383dba 434
8a0681f9
VZ
435 wxToolBarToolsList::Node *node = m_tools.GetFirst();
436 while ( node )
051205e6 437 {
8a0681f9
VZ
438 wxToolBarToolBase *tool = node->GetData();
439 if ( tool->IsButton() )
1c383dba 440 {
f6bcfd97
BP
441 const wxBitmap& bmp = tool->GetBitmap1();
442 if ( bmp.Ok() )
1c383dba 443 {
f6bcfd97
BP
444#if USE_BITMAP_MASKS
445 // notice the last parameter: do use mask
446 dcAllButtons.DrawBitmap(tool->GetBitmap1(), x, 0, TRUE);
447#else // !USE_BITMAP_MASKS
448 HBITMAP hbmp = GetHbitmapOf(bmp);
1c383dba
VZ
449 HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp);
450 if ( !BitBlt(memoryDC, x, 0, m_defaultWidth, m_defaultHeight,
451 memoryDC2, 0, 0, SRCCOPY) )
452 {
f6bcfd97 453 wxLogLastError(wxT("BitBlt"));
1c383dba
VZ
454 }
455
456 ::SelectObject(memoryDC2, oldBitmap2);
f6bcfd97 457#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
1c383dba 458 }
8a0681f9
VZ
459 else
460 {
461 wxFAIL_MSG( _T("invalid tool button bitmap") );
462 }
463
464 // still inc width and number of buttons because otherwise the
465 // subsequent buttons will all be shifted which is rather confusing
466 // (and like this you'd see immediately which bitmap was bad)
467 x += m_defaultWidth;
468 nButtons++;
1c383dba 469 }
8a0681f9
VZ
470
471 node = node->GetNext();
051205e6 472 }
2bda0e17 473
f6bcfd97
BP
474#if USE_BITMAP_MASKS
475 dcAllButtons.SelectObject(wxNullBitmap);
476
477 // don't delete this HBITMAP!
478 bitmap.SetHBITMAP(0);
479#else // !USE_BITMAP_MASKS
1c383dba
VZ
480 ::SelectObject(memoryDC, oldBitmap);
481 ::DeleteDC(memoryDC);
482 ::DeleteDC(memoryDC2);
f6bcfd97 483#endif // USE_BITMAP_MASKS/!USE_BITMAP_MASKS
2bda0e17 484
1c383dba 485 // Map to system colours
566fb299
VZ
486 hBitmap = (HBITMAP)MapBitmap((WXHBITMAP) hBitmap,
487 totalBitmapWidth, totalBitmapHeight);
1c383dba 488
9f83044f
VZ
489 int bitmapId = 0;
490
491 bool addBitmap = TRUE;
492
1c383dba 493 if ( oldToolBarBitmap )
2bda0e17 494 {
9f83044f
VZ
495#ifdef TB_REPLACEBITMAP
496 if ( wxTheApp->GetComCtl32Version() >= 400 )
1c383dba 497 {
9f83044f
VZ
498 TBREPLACEBITMAP replaceBitmap;
499 replaceBitmap.hInstOld = NULL;
500 replaceBitmap.hInstNew = NULL;
501 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
502 replaceBitmap.nIDNew = (UINT) hBitmap;
503 replaceBitmap.nButtons = nButtons;
504 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
505 0, (LPARAM) &replaceBitmap) )
506 {
507 wxFAIL_MSG(wxT("Could not replace the old bitmap"));
508 }
509
510 ::DeleteObject(oldToolBarBitmap);
511
512 // already done
513 addBitmap = FALSE;
1c383dba 514 }
9f83044f
VZ
515 else
516#endif // TB_REPLACEBITMAP
517 {
518 // we can't replace the old bitmap, so we will add another one
519 // (awfully inefficient, but what else to do?) and shift the bitmap
520 // indices accordingly
521 addBitmap = TRUE;
1c383dba 522
9f83044f
VZ
523 bitmapId = m_nButtons;
524 }
1c383dba
VZ
525
526 // Now delete all the buttons
8a0681f9 527 for ( size_t pos = 0; pos < m_nButtons; pos++ )
1c383dba 528 {
8a0681f9
VZ
529 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
530 {
56bd6aac 531 wxLogDebug(wxT("TB_DELETEBUTTON failed"));
8a0681f9 532 }
1c383dba 533 }
9f83044f 534
2bda0e17 535 }
9f83044f
VZ
536
537 if ( addBitmap ) // no old bitmap or we can't replace it
051205e6 538 {
1c383dba
VZ
539 TBADDBITMAP addBitmap;
540 addBitmap.hInst = 0;
8a0681f9 541 addBitmap.nID = (UINT) hBitmap;
1c383dba 542 if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
8a0681f9 543 (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
1c383dba
VZ
544 {
545 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
546 }
051205e6 547 }
2bda0e17 548
8a0681f9
VZ
549 // Next add the buttons and separators
550 // -----------------------------------
551
1c383dba 552 TBBUTTON *buttons = new TBBUTTON[nTools];
2bda0e17 553
8a0681f9 554 // this array will hold the indices of all controls in the toolbar
1c383dba
VZ
555 wxArrayInt controlIds;
556
557 int i = 0;
8a0681f9 558 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
2bda0e17 559 {
8a0681f9
VZ
560 wxToolBarToolBase *tool = node->GetData();
561
562 // don't add separators to the vertical toolbar - looks ugly
563 if ( isVertical && tool->IsSeparator() )
564 continue;
565
1c383dba
VZ
566 TBBUTTON& button = buttons[i];
567
568 wxZeroMemory(button);
569
8a0681f9 570 switch ( tool->GetStyle() )
1c383dba
VZ
571 {
572 case wxTOOL_STYLE_CONTROL:
8a0681f9 573 button.idCommand = tool->GetId();
1c383dba
VZ
574 // fall through: create just a separator too
575
576 case wxTOOL_STYLE_SEPARATOR:
577 button.fsState = TBSTATE_ENABLED;
578 button.fsStyle = TBSTYLE_SEP;
579 break;
580
581 case wxTOOL_STYLE_BUTTON:
582 button.iBitmap = bitmapId;
8a0681f9 583 button.idCommand = tool->GetId();
1c383dba 584
8a0681f9 585 if ( tool->IsEnabled() )
1c383dba 586 button.fsState |= TBSTATE_ENABLED;
8a0681f9 587 if ( tool->IsToggled() )
1c383dba 588 button.fsState |= TBSTATE_CHECKED;
8a0681f9
VZ
589
590 button.fsStyle = tool->CanBeToggled() ? TBSTYLE_CHECK
591 : TBSTYLE_BUTTON;
1c383dba
VZ
592
593 bitmapId++;
594 break;
595 }
2bda0e17 596
1c383dba 597 i++;
2bda0e17 598 }
1c383dba
VZ
599
600 if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS,
601 (WPARAM)i, (LPARAM)buttons) )
2bda0e17 602 {
f6bcfd97 603 wxLogLastError(wxT("TB_ADDBUTTONS"));
2bda0e17 604 }
89b892a2 605
1c383dba 606 delete [] buttons;
2bda0e17 607
8a0681f9
VZ
608 // Deal with the controls finally
609 // ------------------------------
610
1c383dba 611 // adjust the controls size to fit nicely in the toolbar
34e5028f 612 int y = 0;
8a0681f9
VZ
613 size_t index = 0;
614 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
1c383dba 615 {
8a0681f9 616 wxToolBarToolBase *tool = node->GetData();
1c383dba 617
34e5028f
VZ
618 // we calculate the running y coord for vertical toolbars so we need to
619 // get the items size for all items but for the horizontal ones we
620 // don't need to deal with the non controls
621 bool isControl = tool->IsControl();
622 if ( !isControl && !isVertical )
623 continue;
bdc72a22 624
8a0681f9
VZ
625 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
626 // latter only appeared in v4.70 of comctl32.dll
627 RECT r;
628 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
629 index, (LPARAM)(LPRECT)&r) )
630 {
f6bcfd97 631 wxLogLastError(wxT("TB_GETITEMRECT"));
8a0681f9
VZ
632 }
633
34e5028f
VZ
634 if ( !isControl )
635 {
636 // can only be control if isVertical
637 y += r.bottom - r.top;
638
639 continue;
640 }
641
642 wxControl *control = tool->GetControl();
643
644 wxSize size = control->GetSize();
645
646 // the position of the leftmost controls corner
647 int left = -1;
648
bdc72a22 649 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
34e5028f
VZ
650#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
651 // available in headers, now check whether it is available now
652 // (during run-time)
653 if ( wxTheApp->GetComCtl32Version() >= 471 )
654 {
655 // set the (underlying) separators width to be that of the
656 // control
657 TBBUTTONINFO tbbi;
658 tbbi.cbSize = sizeof(tbbi);
659 tbbi.dwMask = TBIF_SIZE;
660 tbbi.cx = size.x;
661 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
662 tool->GetId(), (LPARAM)&tbbi) )
bdc72a22 663 {
34e5028f
VZ
664 // the id is probably invalid?
665 wxLogLastError(wxT("TB_SETBUTTONINFO"));
bdc72a22 666 }
34e5028f
VZ
667 }
668 else
669#endif // comctl32.dll 4.71
670 // TB_SETBUTTONINFO unavailable
671 {
672 // try adding several separators to fit the controls width
673 int widthSep = r.right - r.left;
674 left = r.left;
675
676 TBBUTTON tbb;
677 wxZeroMemory(tbb);
678 tbb.idCommand = 0;
679 tbb.fsState = TBSTATE_ENABLED;
680 tbb.fsStyle = TBSTYLE_SEP;
681
682 size_t nSeparators = size.x / widthSep;
683 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
bdc72a22 684 {
34e5028f
VZ
685 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
686 index, (LPARAM)&tbb) )
bdc72a22 687 {
34e5028f 688 wxLogLastError(wxT("TB_INSERTBUTTON"));
bdc72a22
VZ
689 }
690
34e5028f 691 index++;
bdc72a22 692 }
1c383dba 693
34e5028f
VZ
694 // remember the number of separators we used - we'd have to
695 // delete all of them later
696 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
697
698 // adjust the controls width to exactly cover the separators
699 control->SetSize((nSeparators + 1)*widthSep, -1);
700 }
701
702 // position the control itself correctly vertically
1c383dba
VZ
703 int height = r.bottom - r.top;
704 int diff = height - size.y;
705 if ( diff < 0 )
706 {
707 // the control is too high, resize to fit
708 control->SetSize(-1, height - 2);
709
710 diff = 2;
711 }
2bda0e17 712
34e5028f
VZ
713 int top;
714 if ( isVertical )
715 {
716 left = 0;
717 top = y;
718
719 y += height + 2*GetMargins().y;
720 }
721 else // horizontal toolbar
722 {
723 if ( left == -1 )
724 left = r.left;
725
726 top = r.top;
727 }
728
729 control->Move(left, top + (diff + 1) / 2);
1c383dba 730 }
89b892a2 731
8a0681f9
VZ
732 // the max index is the "real" number of buttons - i.e. counting even the
733 // separators which we added just for aligning the controls
734 m_nButtons = index;
89b892a2 735
8a0681f9
VZ
736 if ( !isVertical )
737 {
738 if ( m_maxRows == 0 )
739 {
740 // if not set yet, only one row
741 SetRows(1);
742 }
743 }
744 else if ( m_nButtons > 0 ) // vertical non empty toolbar
745 {
746 if ( m_maxRows == 0 )
747 {
748 // if not set yet, have one column
749 SetRows(m_nButtons);
750 }
751 }
2bda0e17 752
1c383dba 753 return TRUE;
2bda0e17
KB
754}
755
1c383dba
VZ
756// ----------------------------------------------------------------------------
757// message handlers
758// ----------------------------------------------------------------------------
759
33ac7e6f 760bool wxToolBar::MSWCommand(WXUINT WXUNUSED(cmd), WXWORD id)
2bda0e17 761{
8a0681f9
VZ
762 wxToolBarToolBase *tool = FindById((int)id);
763 if ( !tool )
1c383dba
VZ
764 return FALSE;
765
8a0681f9 766 if ( tool->CanBeToggled() )
1c383dba
VZ
767 {
768 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
82dd98a7 769 tool->Toggle((state & TBSTATE_CHECKED) != 0);
1c383dba
VZ
770 }
771
8a0681f9
VZ
772 bool toggled = tool->IsToggled();
773
774 // OnLeftClick() can veto the button state change - for buttons which may
775 // be toggled only, of couse
776 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
1c383dba 777 {
8a0681f9
VZ
778 // revert back
779 toggled = !toggled;
780 tool->SetToggle(toggled);
781
782 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
1c383dba
VZ
783 }
784
785 return TRUE;
2bda0e17
KB
786}
787
8a0681f9 788bool wxToolBar::MSWOnNotify(int WXUNUSED(idCtrl),
fd3f686c 789 WXLPARAM lParam,
33ac7e6f 790 WXLPARAM *WXUNUSED(result))
2bda0e17 791{
89b892a2 792 // First check if this applies to us
2bda0e17 793 NMHDR *hdr = (NMHDR *)lParam;
2bda0e17 794
1c383dba
VZ
795 // the tooltips control created by the toolbar is sometimes Unicode, even
796 // in an ANSI application - this seems to be a bug in comctl32.dll v5
a17e237f
VZ
797 int code = (int)hdr->code;
798 if ( (code != TTN_NEEDTEXTA) && (code != TTN_NEEDTEXTW) )
89b892a2 799 return FALSE;
2bda0e17 800
89b892a2
VZ
801 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
802 if ( toolTipWnd != hdr->hwndFrom )
803 return FALSE;
2bda0e17 804
89b892a2
VZ
805 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
806 int id = (int)ttText->hdr.idFrom;
89b892a2 807
8a0681f9
VZ
808 wxToolBarToolBase *tool = FindById(id);
809 if ( !tool )
810 return FALSE;
2bda0e17 811
8a0681f9 812 const wxString& help = tool->GetShortHelp();
8df13671
VZ
813
814 if ( !help.IsEmpty() )
89b892a2 815 {
a17e237f 816 if ( code == TTN_NEEDTEXTA )
89b892a2 817 {
837e5743 818 ttText->lpszText = (wxChar *)help.c_str();
89b892a2 819 }
89b892a2
VZ
820 else
821 {
f6bcfd97
BP
822#if wxUSE_UNICODE
823 ttText->lpszText = (wxChar *)help.c_str();
824#else
0d910be7 825 // VZ: I don't know why it happens, but the versions of
56bd6aac 826 // comctl32.dll starting from 4.70 sometimes send TTN_NEEDTEXTW
0d910be7
VZ
827 // even to ANSI programs (normally, this message is supposed
828 // to be sent to Unicode programs only) - hence we need to
829 // handle it as well, otherwise no tooltips will be shown in
830 // this case
8df13671
VZ
831
832 size_t lenAnsi = help.Len();
a9582178 833 #if defined( __MWERKS__ ) || defined( __CYGWIN__ )
8df13671 834 // MetroWerks doesn't like calling mbstowcs with NULL argument
a9582178 835 // neither Cygwin does
8df13671 836 size_t lenUnicode = 2*lenAnsi;
b2cce0c4 837 #else
8df13671 838 size_t lenUnicode = mbstowcs(NULL, help, lenAnsi);
b2cce0c4 839 #endif
8df13671
VZ
840
841 // using the pointer of right type avoids us doing all sorts of
842 // pointer arithmetics ourselves
843 wchar_t *dst = (wchar_t *)ttText->szText,
844 *pwz = new wchar_t[lenUnicode + 1];
845 mbstowcs(pwz, help, lenAnsi + 1);
846 memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
847
848 // put the terminating _wide_ NUL
849 dst[lenUnicode] = 0;
89b892a2
VZ
850
851 delete [] pwz;
f6bcfd97 852#endif
89b892a2 853 }
2bda0e17 854 }
89b892a2 855
89b892a2 856 return TRUE;
2bda0e17
KB
857}
858
1c383dba 859// ----------------------------------------------------------------------------
8a0681f9 860// toolbar geometry
1c383dba
VZ
861// ----------------------------------------------------------------------------
862
8a0681f9 863void wxToolBar::SetToolBitmapSize(const wxSize& size)
2bda0e17 864{
1c383dba
VZ
865 wxToolBarBase::SetToolBitmapSize(size);
866
867 ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
2bda0e17
KB
868}
869
8a0681f9 870void wxToolBar::SetRows(int nRows)
2bda0e17 871{
8a0681f9
VZ
872 if ( nRows == m_maxRows )
873 {
874 // avoid resizing the frame uselessly
875 return;
876 }
877
878 // TRUE in wParam means to create at least as many rows, FALSE -
879 // at most as many
1c383dba
VZ
880 RECT rect;
881 ::SendMessage(GetHwnd(), TB_SETROWS,
8a0681f9
VZ
882 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
883 (LPARAM) &rect);
1c383dba
VZ
884
885 m_maxRows = nRows;
8a0681f9
VZ
886
887 UpdateSize();
888}
889
890// The button size is bigger than the bitmap size
891wxSize wxToolBar::GetToolSize() const
892{
893 // TB_GETBUTTONSIZE is supported from version 4.70
5438a566
VZ
894#if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 ) \
895 && !( defined(__GNUWIN32__) && !wxCHECK_W32API_VERSION( 1, 0 ) )
8a0681f9
VZ
896 if ( wxTheApp->GetComCtl32Version() >= 470 )
897 {
898 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
899
900 return wxSize(LOWORD(dw), HIWORD(dw));
901 }
902 else
903#endif // comctl32.dll 4.70+
904 {
905 // defaults
906 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
907 }
2bda0e17
KB
908}
909
82c9f85c
VZ
910static
911wxToolBarToolBase *GetItemSkippingDummySpacers(const wxToolBarToolsList& tools,
912 size_t index )
a8945eef
MB
913{
914 wxToolBarToolsList::Node* current = tools.GetFirst();
915
82c9f85c 916 for ( ; current != 0; current = current->GetNext() )
a8945eef 917 {
82c9f85c 918 if ( index == 0 )
a8945eef 919 return current->GetData();
82c9f85c
VZ
920
921 wxToolBarTool *tool = (wxToolBarTool *)current->GetData();
922 size_t separators = tool->GetSeparatorsCount();
923
924 // if it is a normal button, sepcount == 0, so skip 1 item (the button)
925 // otherwise, skip as many items as the separator count, plus the
926 // control itself
927 index -= separators ? separators + 1 : 1;
a8945eef
MB
928 }
929
930 return 0;
931}
932
8a0681f9 933wxToolBarToolBase *wxToolBar::FindToolForPosition(wxCoord x, wxCoord y) const
2bda0e17 934{
8a0681f9
VZ
935 POINT pt;
936 pt.x = x;
937 pt.y = y;
938 int index = (int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
37d0bdff
MB
939 // MBN: when the point ( x, y ) is close to the toolbar border
940 // TB_HITTEST returns m_nButtons ( not -1 )
941 if ( index < 0 || (size_t)index >= m_nButtons )
1c383dba 942 {
8a0681f9
VZ
943 // it's a separator or there is no tool at all there
944 return (wxToolBarToolBase *)NULL;
1c383dba
VZ
945 }
946
82c9f85c 947 // if comctl32 version < 4.71 wxToolBar95 adds dummy spacers
a8945eef
MB
948#if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
949 if ( wxTheApp->GetComCtl32Version() >= 471 )
950 {
951 return m_tools.Item((size_t)index)->GetData();
952 }
953 else
82c9f85c 954#endif
a8945eef
MB
955 {
956 return GetItemSkippingDummySpacers( m_tools, (size_t) index );
957 }
2bda0e17
KB
958}
959
8a0681f9 960void wxToolBar::UpdateSize()
2bda0e17 961{
0d7ea902
VZ
962 // the toolbar size changed
963 SendMessage(GetHwnd(), TB_AUTOSIZE, 0, 0);
964
965 // we must also refresh the frame after the toolbar size (possibly) changed
8a0681f9
VZ
966 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
967 if ( frame )
968 {
f6bcfd97 969 frame->SendSizeEvent();
8a0681f9 970 }
2bda0e17
KB
971}
972
1c383dba
VZ
973// ----------------------------------------------------------------------------
974// tool state
975// ----------------------------------------------------------------------------
976
8a0681f9 977void wxToolBar::DoEnableTool(wxToolBarToolBase *tool, bool enable)
2bda0e17 978{
8a0681f9
VZ
979 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
980 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
2bda0e17
KB
981}
982
8a0681f9 983void wxToolBar::DoToggleTool(wxToolBarToolBase *tool, bool toggle)
2bda0e17 984{
8a0681f9
VZ
985 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
986 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
2bda0e17
KB
987}
988
33ac7e6f 989void wxToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle))
088a95f5 990{
8a0681f9
VZ
991 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
992 // without, so we really need to delete the button and recreate it here
993 wxFAIL_MSG( _T("not implemented") );
2bda0e17
KB
994}
995
1c383dba
VZ
996// ----------------------------------------------------------------------------
997// event handlers
998// ----------------------------------------------------------------------------
2bda0e17
KB
999
1000// Responds to colour changes, and passes event on to children.
8a0681f9 1001void wxToolBar::OnSysColourChanged(wxSysColourChangedEvent& event)
2bda0e17 1002{
84c5b38d 1003 wxRGBToColour(m_backgroundColour, ::GetSysColor(COLOR_BTNFACE));
2bda0e17
KB
1004
1005 // Remap the buttons
8a0681f9 1006 Realize();
2bda0e17 1007
56bd6aac
VZ
1008 // Relayout the toolbar
1009 int nrows = m_maxRows;
1010 m_maxRows = 0; // otherwise SetRows() wouldn't do anything
1011 SetRows(nrows);
1012
2bda0e17
KB
1013 Refresh();
1014
56bd6aac
VZ
1015 // let the event propagate further
1016 event.Skip();
2bda0e17
KB
1017}
1018
8a0681f9 1019void wxToolBar::OnMouseEvent(wxMouseEvent& event)
e6460682
JS
1020{
1021 if (event.RightDown())
1022 {
1023 // For now, we don't have an id. Later we could
1024 // try finding the tool.
1025 OnRightClick((int)-1, event.GetX(), event.GetY());
1026 }
1027 else
1028 {
42e69d6b 1029 event.Skip();
e6460682
JS
1030 }
1031}
1032
8a0681f9 1033long wxToolBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
bdc72a22 1034{
8a0681f9 1035 if ( nMsg == WM_SIZE )
bdc72a22 1036 {
8a0681f9
VZ
1037 // calculate our minor dimenstion ourselves - we're confusing the
1038 // standard logic (TB_AUTOSIZE) with our horizontal toolbars and other
1039 // hacks
1040 RECT r;
1041 if ( ::SendMessage(GetHwnd(), TB_GETITEMRECT, 0, (LPARAM)&r) )
1042 {
1043 int w, h;
1044
1045 if ( GetWindowStyle() & wxTB_VERTICAL )
1046 {
1047 w = r.right - r.left;
1048 if ( m_maxRows )
1049 {
1050 w *= (m_nButtons + m_maxRows - 1)/m_maxRows;
1051 }
1052 h = HIWORD(lParam);
1053 }
1054 else
1055 {
1056 w = LOWORD(lParam);
1057 h = r.bottom - r.top;
1058 if ( m_maxRows )
1059 {
1060 h += 6; // FIXME: this is the separator line height...
1061 h *= m_maxRows;
1062 }
1063 }
1064
1065 if ( MAKELPARAM(w, h) != lParam )
1066 {
1067 // size really changed
1068 SetSize(w, h);
1069 }
1070
1071 // message processed
1072 return 0;
1073 }
bdc72a22 1074 }
a8945eef
MB
1075 else if ( nMsg == WM_MOUSEMOVE )
1076 {
1077 wxCoord x = GET_X_LPARAM(lParam), y = GET_Y_LPARAM(lParam);
1078 wxToolBarToolBase* tool = FindToolForPosition( x, y );
1079
1080 // cursor left current tool
1081 if( tool != m_pInTool && !tool )
1082 {
1083 m_pInTool = 0;
1084 OnMouseEnter( -1 );
1085 }
1086
1087 // cursor entered a tool
1088 if( tool != m_pInTool && tool )
1089 {
1090 m_pInTool = tool;
1091 OnMouseEnter( tool->GetId() );
1092 }
1093
1094 // we don't handle mouse moves, so fall through
1095 // to wxControl::MSWWindowProc
1096 }
bdc72a22 1097
8a0681f9 1098 return wxControl::MSWWindowProc(nMsg, wParam, lParam);
bdc72a22
VZ
1099}
1100
1c383dba
VZ
1101// ----------------------------------------------------------------------------
1102// private functions
1103// ----------------------------------------------------------------------------
1104
566fb299 1105WXHBITMAP wxToolBar::MapBitmap(WXHBITMAP bitmap, int width, int height)
2bda0e17 1106{
566fb299
VZ
1107 // number of the colours we map: if you change this, update
1108 // wxBITMAP_STD_COLOURS in the resources as well: it must have the same number
1109 // of pixels
1110 static const size_t NUM_OF_MAPPED_COLOURS = 4;
1111
1112 static bool s_coloursInit = FALSE;
1113 long s_stdColours[NUM_OF_MAPPED_COLOURS];
1114
1115 if (!s_coloursInit)
2bda0e17 1116 {
566fb299
VZ
1117 // When a bitmap is loaded, the RGB values can change (apparently
1118 // because Windows adjusts them to care for the old programs always
1119 // using 0xc0c0c0 while the transparent colour for the new Windows
1120 // versions is different). But we do this adjustment ourselves so we
1121 // want to avoid Windows' "help" and for this we need to have a
5e68f8f3 1122 // reference bitmap which can tell us what the RGB values change to.
566fb299 1123 wxBitmap stdColourBitmap(_T("wxBITMAP_STD_COLOURS"));
5e68f8f3 1124 if (stdColourBitmap.Ok())
2bda0e17 1125 {
5e68f8f3
JS
1126 wxMemoryDC memDC;
1127 memDC.SelectObject(stdColourBitmap);
2bda0e17 1128
5e68f8f3 1129 wxColour colour;
566fb299 1130 for ( size_t i = 0; i < WXSIZEOF(s_stdColours); i++ )
5e68f8f3 1131 {
566fb299
VZ
1132 memDC.GetPixel(i, 0, &colour);
1133 s_stdColours[i] = wxColourToRGB(colour);
5e68f8f3 1134 }
5e68f8f3
JS
1135 }
1136 else
1137 {
566fb299
VZ
1138 s_stdColours[0] = RGB(000,000,000) ;
1139 s_stdColours[1] = RGB(128,128,128) ;
1140 s_stdColours[2] = RGB(192,192,192) ;
1141 s_stdColours[3] = RGB(255,255,255) ;
1142 //s_stdColours[4] = RGB(000,000,255) ;
1143 //s_stdColours[5] = RGB(255,000,255) ;
5e68f8f3 1144 }
56bd6aac 1145
566fb299
VZ
1146 s_coloursInit = TRUE;
1147 }
56bd6aac 1148
566fb299
VZ
1149 COLORMAP ColorMap[NUM_OF_MAPPED_COLOURS];
1150
1151 // black (0, 0 0)
1152 ColorMap[0].from = s_stdColours[0];
1153 ColorMap[0].to = COLOR_BTNTEXT;
1154 // dark grey (128, 128, 128)
1155 ColorMap[1].from = s_stdColours[1];
1156 ColorMap[1].to = COLOR_BTNSHADOW;
1157 // bright grey (192, 192, 192)
1158 ColorMap[2].from = s_stdColours[2];
1159 ColorMap[2].to = COLOR_BTNFACE;
1160 // white (255, 255, 255)
1161 ColorMap[3].from = s_stdColours[3];
1162 ColorMap[3].to = COLOR_BTNHIGHLIGHT;
1163 // blue (0, 0, 255)
1164 // ColorMap[4].from = s_stdColours[4];
1165 // ColorMap[4].to = COLOR_HIGHLIGHT;
1166 // magenta (255, 0, 255)
1167 // ColorMap[4].from = s_stdColours[5];
1168 // ColorMap[4].to = COLOR_WINDOW;
1169
1170 for ( size_t n = 0; n < WXSIZEOF(ColorMap); n++ )
1171 {
1172 ColorMap[n].to = ::GetSysColor(ColorMap[n].to);
1173 }
56bd6aac 1174
566fb299 1175 MemoryHDC hdcMem;
56bd6aac 1176
566fb299 1177 if ( !hdcMem )
5e68f8f3 1178 {
566fb299
VZ
1179 wxLogLastError(_T("CreateCompatibleDC"));
1180
1181 return bitmap;
5e68f8f3 1182 }
56bd6aac 1183
566fb299 1184 SelectInHDC bmpInHDC(hdcMem, (HBITMAP)bitmap);
56bd6aac 1185
566fb299 1186 if ( !bmpInHDC )
5e68f8f3 1187 {
566fb299
VZ
1188 wxLogLastError(_T("SelectObject"));
1189
1190 return bitmap;
1191 }
56bd6aac 1192
566fb299
VZ
1193 // VZ: I leave here my attempts to map the bitmap to the system colours
1194 // faster by using BitBlt() even though it's broken currently - but
1195 // maybe someone else can finish it? It should be faster than iterating
1196 // over all pixels...
1197#if 1
1198 for ( int i = 0; i < width; i++ )
1199 {
1200 for ( int j = 0; j < height; j++ )
5e68f8f3 1201 {
566fb299 1202 COLORREF pixel = ::GetPixel(hdcMem, i, j);
56bd6aac 1203
566fb299
VZ
1204 for ( size_t k = 0; k < WXSIZEOF(ColorMap); k++ )
1205 {
1206 if ( pixel == ColorMap[k].from )
2bda0e17 1207 {
566fb299
VZ
1208 ::SetPixel(hdcMem, i, j, ColorMap[k].to);
1209 break;
2bda0e17
KB
1210 }
1211 }
1212 }
566fb299 1213 }
56bd6aac 1214
566fb299
VZ
1215 return bitmap;
1216#else // 1
1217 MemoryHDC hdcMask, hdcDst;
1218 if ( !hdcMask || !hdcDst )
1219 {
1220 wxLogLastError(_T("CreateCompatibleDC"));
56bd6aac 1221
566fb299 1222 return bitmap;
2bda0e17 1223 }
2bda0e17 1224
566fb299
VZ
1225 // create the target bitmap
1226 HBITMAP hbmpDst = ::CreateCompatibleBitmap(hdcDst, width, height);
1227 if ( !hbmpDst )
1228 {
1229 wxLogLastError(_T("CreateCompatibleBitmap"));
1230
1231 return bitmap;
1232 }
1233
1234 // create the monochrome mask bitmap
1235 HBITMAP hbmpMask = ::CreateBitmap(width, height, 1, 1, 0);
1236 if ( !hbmpMask )
1237 {
1238 wxLogLastError(_T("CreateBitmap(mono)"));
1239
1240 ::DeleteObject(hbmpDst);
1241
1242 return bitmap;
1243 }
1244
1245 SelectInHDC bmpInDst(hdcDst, hbmpDst),
1246 bmpInMask(hdcMask, hbmpMask);
1247
1248 // for each colour:
1249 for ( n = 0; n < NUM_OF_MAPPED_COLOURS; n++ )
1250 {
1251 // create the mask for this colour
1252 ::SetBkColor(hdcMem, ColorMap[n].from);
1253 ::BitBlt(hdcMask, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
1254
1255 // replace this colour with the target one in the dst bitmap
1256 HBRUSH hbr = ::CreateSolidBrush(ColorMap[n].to);
1257 HGDIOBJ hbrOld = ::SelectObject(hdcDst, hbr);
2bda0e17 1258
566fb299
VZ
1259 ::MaskBlt(hdcDst, 0, 0, width, height,
1260 hdcMem, 0, 0,
1261 hbmpMask, 0, 0,
1262 MAKEROP4(PATCOPY, SRCCOPY));
1263
1264 (void)::SelectObject(hdcDst, hbrOld);
1265 ::DeleteObject(hbr);
1266 }
1267
1268 ::DeleteObject((HBITMAP)bitmap);
1269
1270 return (WXHBITMAP)hbmpDst;
1271#endif // 0/1
1272}
2bda0e17 1273
8a0681f9 1274#endif // wxUSE_TOOLBAR && Win95
33ac7e6f 1275