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