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