]> git.saurik.com Git - wxWidgets.git/blame - src/os2/toolbar.cpp
Calling a Refresh() before the window is created no longer
[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
190 ,rName
191 ))
192 return(FALSE);
193
194 // prepare flags
195 DWORD msflags = 0; // WS_VISIBLE | WS_CHILD always included
196 // TODO
197 /*
198
199 if (lStyle & wxBORDER)
200 msflags |= WS_BORDER;
201 msflags |= TBSTYLE_TOOLTIPS;
202
203 if (style & wxTB_FLAT)
204 {
205 if (wxTheApp->GetComCtl32Version() > 400)
206 msflags |= TBSTYLE_FLAT;
207 }
d90895ac 208
b7c2b5c5
DW
209 // MSW-specific initialisation
210 if ( !wxControl::MSWCreateControl(TOOLBARCLASSNAME, msflags) )
211 return FALSE;
212
213 // toolbar-specific post initialisation
214 ::SendMessage(GetHwnd(), TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
215
216 // set up the colors and fonts
217 wxRGBToColour(m_backgroundColour, GetSysColor(COLOR_BTNFACE));
218 m_foregroundColour = *wxBLACK;
219
220 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
221
222 // position it
223 int x = pos.x;
224 int y = pos.y;
225 int width = size.x;
226 int height = size.y;
227
228 if (width <= 0)
229 width = 100;
230 if (height <= 0)
231 height = m_defaultHeight;
232 if (x < 0)
233 x = 0;
234 if (y < 0)
235 y = 0;
236
237 SetSize(x, y, width, height);
238 */
239 return(TRUE);
0e320a79
DW
240}
241
242wxToolBar::~wxToolBar()
243{
b7c2b5c5
DW
244 if (m_hBitmap)
245 {
246 ::GpiDeleteBitmap((HBITMAP) m_hBitmap);
247 }
248}
d90895ac 249
b7c2b5c5
DW
250// ----------------------------------------------------------------------------
251// adding/removing tools
252// ----------------------------------------------------------------------------
253
254bool wxToolBar::DoInsertTool(
255 size_t WXUNUSED(nPos)
256, wxToolBarToolBase* pTool
257)
258{
259 // nothing special to do here - we really create the toolbar buttons in
260 // Realize() later
261 pTool->Attach(this);
262 return(TRUE);
0e320a79
DW
263}
264
b7c2b5c5
DW
265bool wxToolBar::DoDeleteTool(
266 size_t nPos
267, wxToolBarToolBase* pTool
268)
0e320a79 269{
b7c2b5c5
DW
270 // normally, we only delete one button, but we use several separators to
271 // cover the space used by one control sometimes (with old comctl32.dll)
272 size_t nButtonsToDelete = 1;
d90895ac 273
b7c2b5c5
DW
274 // get the size of the button we're going to delete
275 RECTL vRect;
d90895ac 276
b7c2b5c5
DW
277 // TODO:
278 /*
279 if ( !::SendMessage(GetHwnd(), TB_GETITEMRECT, pos, (LPARAM)&r) )
280 {
281 wxLogLastError(_T("TB_GETITEMRECT"));
282 }
d90895ac 283
b7c2b5c5 284 int width = r.right - r.left;
d90895ac 285
b7c2b5c5
DW
286 if ( tool->IsControl() )
287 {
288 nButtonsToDelete = ((wxToolBarTool *)tool)->GetSeparatorsCount();
d90895ac 289
b7c2b5c5
DW
290 width *= nButtonsToDelete;
291 }
292
293 while ( nButtonsToDelete-- > 0 )
d90895ac 294 {
b7c2b5c5
DW
295 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, pos, 0) )
296 {
297 wxLogLastError("TB_DELETEBUTTON");
298
299 return FALSE;
300 }
d90895ac 301 }
d90895ac 302
b7c2b5c5 303 tool->Detach();
d90895ac 304
b7c2b5c5
DW
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() )
d90895ac 310 {
b7c2b5c5
DW
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 }
d90895ac 319 }
b7c2b5c5
DW
320 */
321 return(TRUE);
322}
d90895ac 323
b7c2b5c5
DW
324bool wxToolBar::Realize()
325{
326 size_t nTools = GetToolsCount();
d90895ac 327
b7c2b5c5 328 if (nTools == 0)
d90895ac 329 {
b7c2b5c5
DW
330 // nothing to do
331 return(TRUE);
d90895ac 332 }
b7c2b5c5
DW
333
334 bool bIsVertical = (GetWindowStyle() & wxTB_VERTICAL) != 0;
335
336 // TODO:
337 /*
338 // First, add the bitmap: we use one bitmap for all toolbar buttons
339 // ----------------------------------------------------------------
340
341 // if we already have a bitmap, we'll replace the existing one - otherwise
342 // we'll install a new one
343 HBITMAP oldToolBarBitmap = (HBITMAP)m_hBitmap;
344
345 int totalBitmapWidth = (int)(m_defaultWidth * nTools);
346 int totalBitmapHeight = (int)m_defaultHeight;
347
348 // Create a bitmap for all the tool bitmaps
349 HBITMAP hBitmap = ::CreateCompatibleBitmap(ScreenHDC(),
350 totalBitmapWidth,
351 totalBitmapHeight);
352 if ( !hBitmap )
d90895ac 353 {
b7c2b5c5
DW
354 wxLogLastError(_T("CreateCompatibleBitmap"));
355
356 return FALSE;
d90895ac 357 }
d90895ac 358
b7c2b5c5 359 m_hBitmap = (WXHBITMAP)hBitmap;
d90895ac 360
b7c2b5c5
DW
361 // Now blit all the tools onto this bitmap
362 HDC memoryDC = ::CreateCompatibleDC(NULL);
363 HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, hBitmap);
364
365 HDC memoryDC2 = ::CreateCompatibleDC(NULL);
366
367 // the button position
368 wxCoord x = 0;
369
370 // the number of buttons (not separators)
371 int nButtons = 0;
372
373 wxToolBarToolsList::Node *node = m_tools.GetFirst();
374 while ( node )
d90895ac 375 {
b7c2b5c5
DW
376 wxToolBarToolBase *tool = node->GetData();
377 if ( tool->IsButton() )
378 {
379 HBITMAP hbmp = GetHbitmapOf(tool->GetBitmap1());
380 if ( hbmp )
381 {
382 HBITMAP oldBitmap2 = (HBITMAP)::SelectObject(memoryDC2, hbmp);
383 if ( !BitBlt(memoryDC, x, 0, m_defaultWidth, m_defaultHeight,
384 memoryDC2, 0, 0, SRCCOPY) )
385 {
386 wxLogLastError("BitBlt");
387 }
388
389 ::SelectObject(memoryDC2, oldBitmap2);
390 }
391 else
392 {
393 wxFAIL_MSG( _T("invalid tool button bitmap") );
394 }
d90895ac 395
b7c2b5c5
DW
396 // still inc width and number of buttons because otherwise the
397 // subsequent buttons will all be shifted which is rather confusing
398 // (and like this you'd see immediately which bitmap was bad)
399 x += m_defaultWidth;
400 nButtons++;
401 }
402
403 node = node->GetNext();
d90895ac 404 }
b7c2b5c5
DW
405
406 ::SelectObject(memoryDC, oldBitmap);
407 ::DeleteDC(memoryDC);
408 ::DeleteDC(memoryDC2);
409
410 // Map to system colours
411 wxMapBitmap(hBitmap, totalBitmapWidth, totalBitmapHeight);
412
413 if ( oldToolBarBitmap )
414 {
415 TBREPLACEBITMAP replaceBitmap;
416 replaceBitmap.hInstOld = NULL;
417 replaceBitmap.hInstNew = NULL;
418 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
419 replaceBitmap.nIDNew = (UINT) hBitmap;
420 replaceBitmap.nButtons = nButtons;
421 if ( !::SendMessage(GetHwnd(), TB_REPLACEBITMAP,
422 0, (LPARAM) &replaceBitmap) )
423 {
424 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
425 }
426
427 ::DeleteObject(oldToolBarBitmap);
428
429 // Now delete all the buttons
430 for ( size_t pos = 0; pos < m_nButtons; pos++ )
431 {
432 if ( !::SendMessage(GetHwnd(), TB_DELETEBUTTON, 0, 0) )
433 {
434 wxLogLastError("TB_DELETEBUTTON");
435 }
436 }
437 }
438 else // no old bitmap
d90895ac 439 {
b7c2b5c5
DW
440 TBADDBITMAP addBitmap;
441 addBitmap.hInst = 0;
442 addBitmap.nID = (UINT) hBitmap;
443 if ( ::SendMessage(GetHwnd(), TB_ADDBITMAP,
444 (WPARAM) nButtons, (LPARAM)&addBitmap) == -1 )
445 {
446 wxFAIL_MSG(wxT("Could not add bitmap to toolbar"));
447 }
d90895ac
DW
448 }
449
b7c2b5c5
DW
450 // Next add the buttons and separators
451 // -----------------------------------
d90895ac 452
b7c2b5c5 453 TBBUTTON *buttons = new TBBUTTON[nTools];
d90895ac 454
b7c2b5c5
DW
455 // this array will hold the indices of all controls in the toolbar
456 wxArrayInt controlIds;
d90895ac 457
b7c2b5c5
DW
458 int i = 0;
459 int bitmapId = 0;
460
461 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
462 {
463 wxToolBarToolBase *tool = node->GetData();
d90895ac 464
b7c2b5c5
DW
465 // don't add separators to the vertical toolbar - looks ugly
466 if ( isVertical && tool->IsSeparator() )
467 continue;
468
469 TBBUTTON& button = buttons[i];
470
471 wxZeroMemory(button);
472
473 switch ( tool->GetStyle() )
474 {
475 case wxTOOL_STYLE_CONTROL:
476 button.idCommand = tool->GetId();
477 // fall through: create just a separator too
478
479 case wxTOOL_STYLE_SEPARATOR:
480 button.fsState = TBSTATE_ENABLED;
481 button.fsStyle = TBSTYLE_SEP;
482 break;
483
484 case wxTOOL_STYLE_BUTTON:
485 button.iBitmap = bitmapId;
486 button.idCommand = tool->GetId();
487
488 if ( tool->IsEnabled() )
489 button.fsState |= TBSTATE_ENABLED;
490 if ( tool->IsToggled() )
491 button.fsState |= TBSTATE_CHECKED;
492
493 button.fsStyle = tool->CanBeToggled() ? TBSTYLE_CHECK
494 : TBSTYLE_BUTTON;
495
496 bitmapId++;
497 break;
498 }
499
500 i++;
501 }
502
503 if ( !::SendMessage(GetHwnd(), TB_ADDBUTTONS,
504 (WPARAM)i, (LPARAM)buttons) )
505 {
506 wxLogLastError("TB_ADDBUTTONS");
507 }
508
509 delete [] buttons;
510
511 // Deal with the controls finally
512 // ------------------------------
513
514 // adjust the controls size to fit nicely in the toolbar
515 size_t index = 0;
516 for ( node = m_tools.GetFirst(); node; node = node->GetNext(), index++ )
517 {
518 wxToolBarToolBase *tool = node->GetData();
519 if ( !tool->IsControl() )
520 continue;
521
522 wxControl *control = tool->GetControl();
523
524 wxSize size = control->GetSize();
525
526 // the position of the leftmost controls corner
527 int left = -1;
528
529 // note that we use TB_GETITEMRECT and not TB_GETRECT because the
530 // latter only appeared in v4.70 of comctl32.dll
531 RECT r;
532 if ( !SendMessage(GetHwnd(), TB_GETITEMRECT,
533 index, (LPARAM)(LPRECT)&r) )
534 {
535 wxLogLastError("TB_GETITEMRECT");
536 }
537
538 // TB_SETBUTTONINFO message is only supported by comctl32.dll 4.71+
539 #if defined(_WIN32_IE) && (_WIN32_IE >= 0x400 )
540 // available in headers, now check whether it is available now
541 // (during run-time)
542 if ( wxTheApp->GetComCtl32Version() >= 471 )
543 {
544 // set the (underlying) separators width to be that of the
545 // control
546 TBBUTTONINFO tbbi;
547 tbbi.cbSize = sizeof(tbbi);
548 tbbi.dwMask = TBIF_SIZE;
549 tbbi.cx = size.x;
550 if ( !SendMessage(GetHwnd(), TB_SETBUTTONINFO,
551 tool->GetId(), (LPARAM)&tbbi) )
552 {
553 // the id is probably invalid?
554 wxLogLastError("TB_SETBUTTONINFO");
555 }
556
557 }
558 else
559 #endif // comctl32.dll 4.71
560 // TB_SETBUTTONINFO unavailable
561 {
562 // try adding several separators to fit the controls width
563 int widthSep = r.right - r.left;
564 left = r.left;
565
566 TBBUTTON tbb;
567 wxZeroMemory(tbb);
568 tbb.idCommand = 0;
569 tbb.fsState = TBSTATE_ENABLED;
570 tbb.fsStyle = TBSTYLE_SEP;
571
572 size_t nSeparators = size.x / widthSep;
573 for ( size_t nSep = 0; nSep < nSeparators; nSep++ )
574 {
575 if ( !SendMessage(GetHwnd(), TB_INSERTBUTTON,
576 index, (LPARAM)&tbb) )
577 {
578 wxLogLastError("TB_INSERTBUTTON");
579 }
580
581 index++;
582 }
583
584 // remember the number of separators we used - we'd have to
585 // delete all of them later
586 ((wxToolBarTool *)tool)->SetSeparatorsCount(nSeparators);
587
588 // adjust the controls width to exactly cover the separators
589 control->SetSize((nSeparators + 1)*widthSep, -1);
590 }
591
592 // and position the control itself correctly vertically
593 int height = r.bottom - r.top;
594 int diff = height - size.y;
595 if ( diff < 0 )
596 {
597 // the control is too high, resize to fit
598 control->SetSize(-1, height - 2);
599
600 diff = 2;
601 }
602
603 control->Move(left == -1 ? r.left : left, r.top + (diff + 1) / 2);
604 }
605
606 // the max index is the "real" number of buttons - i.e. counting even the
607 // separators which we added just for aligning the controls
608 m_nButtons = index;
609
610 if ( !isVertical )
611 {
612 if ( m_maxRows == 0 )
613 {
614 // if not set yet, only one row
615 SetRows(1);
616 }
617 }
618 else if ( m_nButtons > 0 ) // vertical non empty toolbar
619 {
620 if ( m_maxRows == 0 )
621 {
622 // if not set yet, have one column
623 SetRows(m_nButtons);
624 }
625 }
626 */
627 return TRUE;
d90895ac
DW
628}
629
b7c2b5c5
DW
630// ----------------------------------------------------------------------------
631// message handlers
632// ----------------------------------------------------------------------------
633
634bool wxToolBar::OS2Command(
635 WXUINT nCmd
636, WXWORD nId
637)
d90895ac 638{
b7c2b5c5
DW
639 wxToolBarToolBase* pTool = FindById((int)nId);
640
641 if (!pTool)
642 return(FALSE);
643 // TODO:
644 /*
645 if (pTool->CanBeToggled())
646 {
647 LRESULT state = ::SendMessage(GetHwnd(), TB_GETSTATE, id, 0);
648 tool->SetToggle((state & TBSTATE_CHECKED) != 0);
649 }
650
651 bool toggled = tool->IsToggled();
652
653 // OnLeftClick() can veto the button state change - for buttons which may
654 // be toggled only, of couse
655 if ( !OnLeftClick((int)id, toggled) && tool->CanBeToggled() )
656 {
657 // revert back
658 toggled = !toggled;
659 tool->SetToggle(toggled);
660
661 ::SendMessage(GetHwnd(), TB_CHECKBUTTON, id, MAKELONG(toggled, 0));
662 }
663 */
664 return(TRUE);
d90895ac
DW
665}
666
b7c2b5c5
DW
667bool wxToolBar::OS2OnNotify(
668 int WXUNUSED(idCtrl)
669, WXLPARAM lParam
670, WXLPARAM* pResult
671)
d90895ac 672{
b7c2b5c5
DW
673 // TODO:
674 /*
d90895ac
DW
675 // First check if this applies to us
676 NMHDR *hdr = (NMHDR *)lParam;
677
b7c2b5c5
DW
678 // the tooltips control created by the toolbar is sometimes Unicode, even
679 // in an ANSI application - this seems to be a bug in comctl32.dll v5
d90895ac
DW
680 int code = (int)hdr->code;
681 if ( (code != TTN_NEEDTEXTA) && (code != TTN_NEEDTEXTW) )
682 return FALSE;
683
684 HWND toolTipWnd = (HWND)::SendMessage((HWND)GetHWND(), TB_GETTOOLTIPS, 0, 0);
685 if ( toolTipWnd != hdr->hwndFrom )
0e320a79
DW
686 return FALSE;
687
d90895ac
DW
688 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT)lParam;
689 int id = (int)ttText->hdr.idFrom;
d90895ac 690
b7c2b5c5
DW
691 wxToolBarToolBase *tool = FindById(id);
692 if ( !tool )
693 return FALSE;
d90895ac 694
b7c2b5c5 695 const wxString& help = tool->GetShortHelp();
d90895ac
DW
696
697 if ( !help.IsEmpty() )
698 {
699 if ( code == TTN_NEEDTEXTA )
700 {
701 ttText->lpszText = (wxChar *)help.c_str();
702 }
703#if (_WIN32_IE >= 0x0300)
704 else
705 {
706 // FIXME this is a temp hack only until I understand better what
707 // must be done in both ANSI and Unicode builds
708
709 size_t lenAnsi = help.Len();
710 #ifdef __MWERKS__
711 // MetroWerks doesn't like calling mbstowcs with NULL argument
712 size_t lenUnicode = 2*lenAnsi;
713 #else
714 size_t lenUnicode = mbstowcs(NULL, help, lenAnsi);
715 #endif
716
717 // using the pointer of right type avoids us doing all sorts of
718 // pointer arithmetics ourselves
719 wchar_t *dst = (wchar_t *)ttText->szText,
720 *pwz = new wchar_t[lenUnicode + 1];
721 mbstowcs(pwz, help, lenAnsi + 1);
722 memcpy(dst, pwz, lenUnicode*sizeof(wchar_t));
723
724 // put the terminating _wide_ NUL
725 dst[lenUnicode] = 0;
726
727 delete [] pwz;
728 }
729#endif // _WIN32_IE >= 0x0300
730 }
731
732 // For backward compatibility...
b7c2b5c5
DW
733 OnMouseEnter(tool->GetId());
734 */
735 return(TRUE);
0e320a79
DW
736}
737
b7c2b5c5
DW
738// ----------------------------------------------------------------------------
739// toolbar geometry
740// ----------------------------------------------------------------------------
d90895ac 741
b7c2b5c5
DW
742void wxToolBar::SetToolBitmapSize(
743 const wxSize& rSize
744)
d90895ac 745{
b7c2b5c5
DW
746 wxToolBarBase::SetToolBitmapSize(rSize);
747
748 // ::SendMessage(GetHwnd(), TB_SETBITMAPSIZE, 0, MAKELONG(size.x, size.y));
0e320a79
DW
749}
750
b7c2b5c5
DW
751void wxToolBar::SetRows(
752 int nRows
753)
0e320a79 754{
b7c2b5c5
DW
755 if (nRows == m_maxRows)
756 {
757 // avoid resizing the frame uselessly
758 return;
759 }
760 // TODO:
761 /*
762 // TRUE in wParam means to create at least as many rows, FALSE -
763 // at most as many
d90895ac 764 RECT rect;
b7c2b5c5
DW
765 ::SendMessage(GetHwnd(), TB_SETROWS,
766 MAKEWPARAM(nRows, !(GetWindowStyle() & wxTB_VERTICAL)),
767 (LPARAM) &rect);
768
769 m_maxRows = nRows;
770
771 UpdateSize();
772 */
0e320a79
DW
773}
774
775// The button size is bigger than the bitmap size
776wxSize wxToolBar::GetToolSize() const
777{
b7c2b5c5
DW
778 // TODO:
779 /*
780 // TB_GETBUTTONSIZE is supported from version 4.70
781#if defined(_WIN32_IE) && (_WIN32_IE >= 0x300 )
782 if ( wxTheApp->GetComCtl32Version() >= 470 )
783 {
784 DWORD dw = ::SendMessage(GetHwnd(), TB_GETBUTTONSIZE, 0, 0);
785
786 return wxSize(LOWORD(dw), HIWORD(dw));
787 }
788 else
789#endif // comctl32.dll 4.70+
790 {
791 // defaults
792 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
793 }
794 */
795 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
0e320a79
DW
796}
797
b7c2b5c5
DW
798wxToolBarToolBase *wxToolBar::FindToolForPosition(
799 wxCoord vX
800, wxCoord vY
801) const
0e320a79 802{
b7c2b5c5
DW
803 POINTL vPt;
804
805 vPt.x = vX;
806 vPt.y = vY;
807
808 int nIndex = 0; //(int)::SendMessage(GetHwnd(), TB_HITTEST, 0, (LPARAM)&pt);
809 if (nIndex < 0)
810 {
811 // it's a separator or there is no tool at all there
812 return (wxToolBarToolBase *)NULL;
813 }
814 return(m_tools.Item((size_t)nIndex)->GetData());
0e320a79
DW
815}
816
b7c2b5c5 817void wxToolBar::UpdateSize()
0e320a79 818{
b7c2b5c5
DW
819 // we must refresh the frame after the toolbar size (possibly) changed
820 wxFrame* pFrame = wxDynamicCast(GetParent(), wxFrame);
821
822 if (pFrame)
0e320a79 823 {
b7c2b5c5
DW
824 // don't change the size, we just need to generate a WM_SIZE
825 RECTL vR;
826 // TODO:
827 /*
828 if ( !GetWindowRect(GetHwndOf(frame), &r) )
829 {
830 wxLogLastError(_T("GetWindowRect"));
831 }
832
833 (void)::SendMessage(GetHwndOf(frame), WM_SIZE, SIZE_RESTORED,
834 MAKELPARAM(r.right - r.left, r.bottom - r.top));
835 */
0e320a79 836 }
d90895ac
DW
837}
838
b7c2b5c5
DW
839// ----------------------------------------------------------------------------
840// tool state
841// ----------------------------------------------------------------------------
842
843void wxToolBar::DoEnableTool(
844 wxToolBarToolBase* pTool
845, bool bEnable
846)
d90895ac 847{
b7c2b5c5
DW
848 // TODO:
849 /*
850 ::SendMessage(GetHwnd(), TB_ENABLEBUTTON,
851 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(enable, 0));
852 */
0e320a79
DW
853}
854
b7c2b5c5
DW
855void wxToolBar::DoToggleTool(
856 wxToolBarToolBase* pTool
857, bool bToggle
858)
0e320a79 859{
b7c2b5c5
DW
860 // TODO:
861 /*
862 ::SendMessage(GetHwnd(), TB_CHECKBUTTON,
863 (WPARAM)tool->GetId(), (LPARAM)MAKELONG(toggle, 0));
864 */
0e320a79
DW
865}
866
b7c2b5c5
DW
867void wxToolBar::DoSetToggle(
868 wxToolBarToolBase* pTool
869, bool bToggle
870)
0e320a79 871{
b7c2b5c5
DW
872 // VZ: AFAIK, the button has to be created either with TBSTYLE_CHECK or
873 // without, so we really need to delete the button and recreate it here
874 wxFAIL_MSG( _T("not implemented") );
0e320a79
DW
875}
876
b7c2b5c5
DW
877// ----------------------------------------------------------------------------
878// event handlers
879// ----------------------------------------------------------------------------
880
d90895ac 881// Responds to colour changes, and passes event on to children.
b7c2b5c5
DW
882void wxToolBar::OnSysColourChanged(
883 wxSysColourChangedEvent& rEvent
884)
d90895ac 885{
b7c2b5c5
DW
886 // TODO:
887 /*
d90895ac
DW
888 m_backgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
889 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
b7c2b5c5
DW
890 */
891
d90895ac 892 // Remap the buttons
b7c2b5c5 893 Realize();
d90895ac
DW
894
895 Refresh();
896
897 // Propagate the event to the non-top-level children
b7c2b5c5 898 wxWindow::OnSysColourChanged(rEvent);
d90895ac
DW
899}
900
b7c2b5c5
DW
901void wxToolBar::OnMouseEvent(
902 wxMouseEvent& rEvent
903)
d90895ac 904{
b7c2b5c5 905 if (rEvent.RightDown())
d90895ac
DW
906 {
907 // For now, we don't have an id. Later we could
908 // try finding the tool.
b7c2b5c5
DW
909 OnRightClick( (int)-1
910 ,rEvent.GetX()
911 ,rEvent.GetY()
912 );
d90895ac
DW
913 }
914 else
915 {
b7c2b5c5
DW
916 rEvent.Skip();
917 }
918}
919
920MRESULT wxToolBar::OS2WindowProc(
921 HWND hWnd
922, WXUINT ulMsg
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