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