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