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