]> git.saurik.com Git - wxWidgets.git/blob - src/msw/tbar95.cpp
Removed compile bugs in regconf.cpp, added new toolbar event processing
[wxWidgets.git] / src / msw / tbar95.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tbar95.cpp
3 // Purpose: wxToolBar95
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "tbar95.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx.h"
25 #endif
26
27 #if USE_BUTTONBAR && USE_TOOLBAR && defined(__WIN95__)
28
29 #ifndef __GNUWIN32__
30 #include "malloc.h"
31 #endif
32
33 #include <windows.h>
34
35 #ifndef __GNUWIN32__
36 #include <commctrl.h>
37 #endif
38
39 #ifdef __GNUWIN32__
40 #include "wx/msw/gnuwin32/extra.h"
41 #endif
42
43 #include "wx/msw/dib.h"
44 #include "wx/tbar95.h"
45 #include "wx/app.h"
46 #include "wx/msw/private.h"
47
48 // Styles
49 #ifndef TBSTYLE_FLAT
50 #define TBSTYLE_LIST 0x1000
51 #define TBSTYLE_FLAT 0x0800
52 #define TBSTYLE_TRANSPARENT 0x8000
53 #endif
54 // use TBSTYLE_TRANSPARENT if you use TBSTYLE_FLAT
55
56 // Messages
57 #ifndef TB_GETSTYLE
58 #define TB_GETSTYLE (WM_USER + 57)
59 #define TB_SETSTYLE (WM_USER + 56)
60 #endif
61
62 /* Hint from a newsgroup for custom flatbar drawing:
63 Set the TBSTYLE_CUSTOMERASE style, then handle the
64 NM_CUSTOMDRAW message and do your custom drawing.
65 */
66
67 #if !USE_SHARED_LIBRARY
68 IMPLEMENT_DYNAMIC_CLASS(wxToolBar95, wxToolBarBase)
69
70 BEGIN_EVENT_TABLE(wxToolBar95, wxToolBarBase)
71 EVT_SIZE(wxToolBar95::OnSize)
72 EVT_PAINT(wxToolBar95::OnPaint)
73 EVT_KILL_FOCUS(wxToolBar95::OnKillFocus)
74 EVT_MOUSE_EVENTS(wxToolBar95::OnMouseEvent)
75 EVT_SYS_COLOUR_CHANGED(wxToolBar95::OnSysColourChanged)
76 END_EVENT_TABLE()
77 #endif
78
79 void wxMapBitmap(HBITMAP hBitmap, int width, int height);
80
81 wxToolBar95::wxToolBar95(void)
82 {
83 m_tilingDirection = wxVERTICAL ;
84 m_rowsOrColumns = 0;
85 m_currentRowsOrColumns = 0;
86 m_maxWidth = -1;
87 m_maxHeight = -1;
88 m_hBitmap = 0;
89 m_defaultWidth = DEFAULTBITMAPX;
90 m_defaultHeight = DEFAULTBITMAPY;
91 }
92
93 bool wxToolBar95::Create(wxWindow *parent, wxWindowID id, const wxPoint& pos, const wxSize& size,
94 long style, int orientation,
95 int RowsOrColumns, const wxString& name)
96 {
97 m_backgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
98 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
99 m_foregroundColour = *wxBLACK ;
100
101 m_defaultForegroundColour = *wxBLACK ;
102 m_defaultBackgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
103 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
104
105 m_tilingDirection = orientation;
106 if (m_tilingDirection == wxHORIZONTAL)
107 wxMessageBox("Sorry, wxToolBar95 under Windows 95 only supports vertical tiling.\nPass the number of rows.", "wxToolBar95 usage", wxOK);
108 m_rowsOrColumns = RowsOrColumns;
109 m_currentRowsOrColumns = 0;
110 m_maxWidth = -1;
111 m_maxHeight = -1;
112
113 m_hBitmap = 0;
114
115 m_defaultWidth = DEFAULTBITMAPX;
116 m_defaultHeight = DEFAULTBITMAPY;
117 SetName(name);
118
119 int x = pos.x;
120 int y = pos.y;
121 int width = size.x;
122 int height = size.y;
123
124 m_windowStyle = style;
125
126 SetFont(wxSystemSettings::GetSystemFont(wxSYS_DEFAULT_GUI_FONT));
127
128 SetParent(parent);
129
130 DWORD msflags = 0;
131 if (style & wxBORDER)
132 msflags |= WS_BORDER;
133 msflags |= WS_CHILD | WS_VISIBLE;
134
135 if (width <= 0)
136 width = 100;
137 if (height <= 0)
138 height = 30;
139 if (x < 0)
140 x = 0;
141 if (y < 0)
142 y = 0;
143
144 m_windowId = (id < 0 ? NewControlId() : id);
145 DWORD msStyle = WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS;
146
147 if (style & wxTB_FLAT)
148 {
149 if (wxTheApp->GetComCtl32Version() > 400)
150 msStyle |= TBSTYLE_FLAT;
151 }
152
153 // Create the toolbar control.
154 HWND hWndToolbar = CreateWindowEx(0L, // No extended styles.
155 TOOLBARCLASSNAME, // Class name for the toolbar.
156 "", // No default text.
157 msStyle, // Styles and defaults.
158 x, y, width, height, // Standard toolbar size and position.
159 (HWND) parent->GetHWND(), // Parent window of the toolbar.
160 (HMENU)m_windowId, // Toolbar ID.
161 wxGetInstance(), // Current instance.
162 NULL ); // No class data.
163
164 // Toolbar-specific initialisation
165 ::SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), (LPARAM)0);
166
167 m_hWnd = (WXHWND) hWndToolbar;
168 if (parent) parent->AddChild(this);
169
170 SubclassWin((WXHWND) hWndToolbar);
171
172 return TRUE;
173 }
174
175 wxToolBar95::~wxToolBar95(void)
176 {
177 UnsubclassWin();
178
179 if (m_hBitmap)
180 {
181 ::DeleteObject((HBITMAP) m_hBitmap);
182 m_hBitmap = 0;
183 }
184 }
185
186 bool wxToolBar95::CreateTools(void)
187 {
188 if (m_tools.Number() == 0)
189 return FALSE;
190
191 HBITMAP oldToolBarBitmap = (HBITMAP) m_hBitmap;
192
193 int totalBitmapWidth = (int)(m_defaultWidth * m_tools.Number());
194 int totalBitmapHeight = (int)m_defaultHeight;
195
196 // Create a bitmap for all the tool bitmaps
197 HDC dc = ::GetDC(NULL);
198 m_hBitmap = (WXHBITMAP) ::CreateCompatibleBitmap(dc, totalBitmapWidth, totalBitmapHeight);
199 ::ReleaseDC(NULL, dc);
200
201 // Now blit all the tools onto this bitmap
202 HDC memoryDC = ::CreateCompatibleDC(NULL);
203 HBITMAP oldBitmap = (HBITMAP) ::SelectObject(memoryDC, (HBITMAP) m_hBitmap);
204
205 HDC memoryDC2 = ::CreateCompatibleDC(NULL);
206 int x = 0;
207 wxNode *node = m_tools.First();
208 int noButtons = 0;
209 while (node)
210 {
211 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
212 if ((tool->m_toolStyle != wxTOOL_STYLE_SEPARATOR) && tool->m_bitmap1.Ok() && tool->m_bitmap1.GetHBITMAP())
213 {
214 // wxPalette *palette = tool->m_bitmap1->GetPalette();
215
216 HBITMAP oldBitmap2 = (HBITMAP) ::SelectObject(memoryDC2, (HBITMAP) tool->m_bitmap1.GetHBITMAP());
217 /* int bltResult = */
218 BitBlt(memoryDC, x, 0, (int) m_defaultWidth, (int) m_defaultHeight, memoryDC2,
219 0, 0, SRCCOPY);
220 ::SelectObject(memoryDC2, oldBitmap2);
221 x += (int)m_defaultWidth;
222 noButtons ++;
223 }
224 node = node->Next();
225 }
226 ::SelectObject(memoryDC, oldBitmap);
227 ::DeleteDC(memoryDC);
228 ::DeleteDC(memoryDC2);
229
230 // Map to system colours
231 wxMapBitmap((HBITMAP) m_hBitmap, totalBitmapWidth, totalBitmapHeight);
232
233 if ( oldToolBarBitmap )
234 {
235 TBREPLACEBITMAP replaceBitmap;
236 replaceBitmap.hInstOld = NULL;
237 replaceBitmap.hInstNew = NULL;
238 replaceBitmap.nIDOld = (UINT) oldToolBarBitmap;
239 replaceBitmap.nIDNew = (UINT) (HBITMAP) m_hBitmap;
240 replaceBitmap.nButtons = noButtons;
241 if (::SendMessage((HWND) GetHWND(), TB_REPLACEBITMAP, (WPARAM) 0, (LPARAM) &replaceBitmap) == -1)
242 wxMessageBox("Could not add bitmap to toolbar");
243
244 ::DeleteObject((HBITMAP) oldToolBarBitmap);
245
246 // Now delete all the buttons
247 int i = 0;
248 while ( TRUE )
249 {
250 // TODO: What about separators???? They don't have an id!
251 if ( ! ::SendMessage( (HWND) GetHWND(), TB_DELETEBUTTON, i, 0 ) )
252 break;
253 }
254 }
255 else
256 {
257 TBADDBITMAP addBitmap;
258 addBitmap.hInst = 0;
259 addBitmap.nID = (UINT)m_hBitmap;
260 if (::SendMessage((HWND) GetHWND(), TB_ADDBITMAP, (WPARAM) noButtons, (LPARAM) &addBitmap) == -1)
261 wxMessageBox("Could not add bitmap to toolbar");
262 }
263
264 // Now add the buttons.
265 TBBUTTON buttons[50];
266
267 node = m_tools.First();
268 int i = 0;
269 int bitmapId = 0;
270 while (node)
271 {
272 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
273 if (tool->m_toolStyle == wxTOOL_STYLE_SEPARATOR)
274 {
275 buttons[i].iBitmap = 0;
276 buttons[i].idCommand = 0;
277
278 buttons[i].fsState = TBSTATE_ENABLED;
279 buttons[i].fsStyle = TBSTYLE_SEP;
280 buttons[i].dwData = 0L;
281 buttons[i].iString = 0;
282 }
283 else
284 {
285 buttons[i].iBitmap = bitmapId;
286 buttons[i].idCommand = tool->m_index;
287
288 buttons[i].fsState = 0;
289 if (tool->m_enabled)
290 buttons[i].fsState |= TBSTATE_ENABLED;
291 if (tool->m_toggleState)
292 buttons[i].fsState |= TBSTATE_CHECKED;
293 buttons[i].fsStyle = tool->m_isToggle ? TBSTYLE_CHECK : TBSTYLE_BUTTON;
294 buttons[i].dwData = 0L;
295 buttons[i].iString = 0;
296
297 bitmapId ++;
298 }
299
300 i ++;
301 node = node->Next();
302 }
303
304 int ans = (int)::SendMessage((HWND) GetHWND(), TB_ADDBUTTONS, (WPARAM)i, (LPARAM)& buttons);
305 ans = (int)::SendMessage((HWND) GetHWND(), TB_AUTOSIZE, (WPARAM)0, (LPARAM) 0);
306
307 RECT rect;
308 ::SendMessage((HWND) GetHWND(), TB_SETROWS, MAKEWPARAM(m_rowsOrColumns, TRUE), (LPARAM) & rect);
309 m_maxWidth = (rect.right - rect.left + 2);
310 m_maxHeight = (rect.bottom - rect.top + 2);
311
312 return TRUE;
313 }
314
315 bool wxToolBar95::MSWCommand(WXUINT cmd, WXWORD id)
316 {
317 wxNode *node = m_tools.Find((long)id);
318 if (!node)
319 return FALSE;
320 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
321 if (tool->m_isToggle)
322 tool->m_toggleState = (1 == (1 & (int)::SendMessage((HWND) GetHWND(), TB_GETSTATE, (WPARAM) id, (LPARAM) 0)));
323
324 BOOL ret = OnLeftClick((int)id, tool->m_toggleState);
325 if (ret == FALSE && tool->m_isToggle)
326 {
327 tool->m_toggleState = !tool->m_toggleState;
328 ::SendMessage((HWND) GetHWND(), TB_CHECKBUTTON, (WPARAM)id, (LPARAM)MAKELONG(tool->m_toggleState, 0));
329 }
330 return TRUE;
331 }
332
333 bool wxToolBar95::MSWNotify(WXWPARAM WXUNUSED(wParam), WXLPARAM lParam)
334 {
335 // First check if this applies to us
336 NMHDR *hdr = (NMHDR *)lParam;
337 if (hdr->code != TTN_NEEDTEXT)
338 return FALSE;
339
340 HWND toolTipWnd = (HWND) ::SendMessage((HWND) GetHWND(), TB_GETTOOLTIPS, 0, 0);
341 if ( toolTipWnd != hdr->hwndFrom )
342 return FALSE;
343
344 LPTOOLTIPTEXT ttText = (LPTOOLTIPTEXT) lParam;
345 int id = (int)ttText->hdr.idFrom;
346 wxNode *node = m_tools.Find((long)id);
347 if (!node)
348 return FALSE;
349
350 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
351
352 switch (ttText->hdr.code)
353 {
354 case TTN_NEEDTEXT:
355 {
356 if (tool->m_shortHelpString != "")
357 ttText->lpszText = (char *) (const char *)tool->m_shortHelpString;
358
359 // For backward compatibility...
360 OnMouseEnter(tool->m_index);
361 break;
362 }
363 default:
364 return FALSE;
365 break;
366 }
367
368 return TRUE;
369 }
370
371 void wxToolBar95::SetDefaultSize(const wxSize& size)
372 {
373 m_defaultWidth = size.x; m_defaultHeight = size.y;
374 ::SendMessage((HWND) GetHWND(), TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG ((int)size.x, (int)size.y));
375 }
376
377 void wxToolBar95::SetRows(int nRows)
378 {
379 RECT rect;
380 ::SendMessage((HWND) GetHWND(), TB_SETROWS, MAKEWPARAM(nRows, TRUE), (LPARAM) & rect);
381 m_maxWidth = (rect.right - rect.left + 2);
382 m_maxHeight = (rect.bottom - rect.top + 2);
383 }
384
385 wxSize wxToolBar95::GetMaxSize(void) const
386 {
387 if (m_maxWidth == -1 | m_maxHeight == -1)
388 {
389 RECT rect;
390 ::SendMessage((HWND) GetHWND(), TB_SETROWS, MAKEWPARAM(m_rowsOrColumns, TRUE), (LPARAM) & rect);
391 ((wxToolBar95 *)this)->m_maxWidth = (rect.right - rect.left + 2); // ???
392 ((wxToolBar95 *)this)->m_maxHeight = (rect.bottom - rect.top + 2); // ???
393 }
394 return wxSize(m_maxWidth, m_maxHeight);
395 }
396
397 void wxToolBar95::GetSize(int *w, int *h) const
398 {
399 wxWindow::GetSize(w, h);
400 // For some reason, the returned height is several pixels bigger than that
401 // displayed!
402 *h -= 2;
403 }
404
405 // The button size is bigger than the bitmap size
406 wxSize wxToolBar95::GetDefaultButtonSize(void) const
407 {
408 return wxSize(m_defaultWidth + 8, m_defaultHeight + 7);
409 }
410
411 void wxToolBar95::EnableTool(int toolIndex, bool enable)
412 {
413 wxNode *node = m_tools.Find((long)toolIndex);
414 if (node)
415 {
416 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
417 tool->m_enabled = enable;
418 ::SendMessage((HWND) GetHWND(), TB_ENABLEBUTTON, (WPARAM)toolIndex, (LPARAM)MAKELONG(enable, 0));
419 }
420 }
421
422 void wxToolBar95::ToggleTool(int toolIndex, bool toggle)
423 {
424 wxNode *node = m_tools.Find((long)toolIndex);
425 if (node)
426 {
427 wxToolBarTool *tool = (wxToolBarTool *)node->Data();
428 if (tool->m_isToggle)
429 {
430 tool->m_toggleState = toggle;
431 ::SendMessage((HWND) GetHWND(), TB_CHECKBUTTON, (WPARAM)toolIndex, (LPARAM)MAKELONG(toggle, 0));
432 }
433 }
434 }
435
436 void wxToolBar95::ClearTools(void)
437 {
438 // TODO: Don't know how to reset the toolbar bitmap, as yet.
439 // But adding tools and calling CreateTools should probably
440 // recreate a buttonbar OK.
441 wxToolBarBase::ClearTools();
442 }
443
444 // If pushedBitmap is NULL, a reversed version of bitmap is
445 // created and used as the pushed/toggled image.
446 // If toggle is TRUE, the button toggles between the two states.
447 wxToolBarTool *wxToolBar95::AddTool(int index, const wxBitmap& bitmap, const wxBitmap& pushedBitmap,
448 bool toggle, long xPos, long yPos, wxObject *clientData, const wxString& helpString1, const wxString& helpString2)
449 {
450 wxToolBarTool *tool = new wxToolBarTool(index, bitmap, (wxBitmap *)NULL, toggle, xPos, yPos, helpString1, helpString2);
451 tool->m_clientData = clientData;
452
453 if (xPos > -1)
454 tool->m_x = xPos;
455 else
456 tool->m_x = m_xMargin;
457
458 if (yPos > -1)
459 tool->m_y = yPos;
460 else
461 tool->m_y = m_yMargin;
462
463 tool->SetSize(GetDefaultButtonWidth(), GetDefaultButtonHeight());
464
465 m_tools.Append((long)index, tool);
466 return tool;
467 }
468
469 // Responds to colour changes, and passes event on to children.
470 void wxToolBar95::OnSysColourChanged(wxSysColourChangedEvent& event)
471 {
472 m_backgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
473 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
474 m_defaultBackgroundColour = wxColour(GetRValue(GetSysColor(COLOR_BTNFACE)),
475 GetGValue(GetSysColor(COLOR_BTNFACE)), GetBValue(GetSysColor(COLOR_BTNFACE)));
476
477 // Remap the buttons
478 CreateTools();
479
480 Default();
481
482 Refresh();
483
484 // Propagate the event to the non-top-level children
485 wxWindow::OnSysColourChanged(event);
486 }
487
488 // These are the default colors used to map the bitmap colors
489 // to the current system colors
490
491 #define BGR_BUTTONTEXT (RGB(000,000,000)) // black
492 #define BGR_BUTTONSHADOW (RGB(128,128,128)) // dark grey
493 #define BGR_BUTTONFACE (RGB(192,192,192)) // bright grey
494 #define BGR_BUTTONHILIGHT (RGB(255,255,255)) // white
495 #define BGR_BACKGROUNDSEL (RGB(255,000,000)) // blue
496 #define BGR_BACKGROUND (RGB(255,000,255)) // magenta
497
498 void wxMapBitmap(HBITMAP hBitmap, int width, int height)
499 {
500 COLORMAP ColorMap[] = {
501 {BGR_BUTTONTEXT, COLOR_BTNTEXT}, // black
502 {BGR_BUTTONSHADOW, COLOR_BTNSHADOW}, // dark grey
503 {BGR_BUTTONFACE, COLOR_BTNFACE}, // bright grey
504 {BGR_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT},// white
505 {BGR_BACKGROUNDSEL, COLOR_HIGHLIGHT}, // blue
506 {BGR_BACKGROUND, COLOR_WINDOW} // magenta
507 };
508
509 int NUM_MAPS = (sizeof(ColorMap)/sizeof(COLORMAP));
510 int n;
511 for ( n = 0; n < NUM_MAPS; n++)
512 {
513 ColorMap[n].to = ::GetSysColor(ColorMap[n].to);
514 }
515
516 HBITMAP hbmOld;
517 HDC hdcMem = CreateCompatibleDC(NULL);
518
519 if (hdcMem)
520 {
521 hbmOld = (HBITMAP) SelectObject(hdcMem, hBitmap);
522
523 int i, j, k;
524 for ( i = 0; i < width; i++)
525 {
526 for ( j = 0; j < height; j++)
527 {
528 COLORREF pixel = ::GetPixel(hdcMem, i, j);
529 /*
530 BYTE red = GetRValue(pixel);
531 BYTE green = GetGValue(pixel);
532 BYTE blue = GetBValue(pixel);
533 */
534
535 for ( k = 0; k < NUM_MAPS; k ++)
536 {
537 if ( ColorMap[k].from == pixel )
538 {
539 /* COLORREF actualPixel = */ ::SetPixel(hdcMem, i, j, ColorMap[k].to);
540 break;
541 }
542 }
543 }
544 }
545
546
547 SelectObject(hdcMem, hbmOld);
548 DeleteObject(hdcMem);
549 }
550
551 }
552
553 // Some experiments...
554 #if 0
555 // What we want to do is create another bitmap which has a depth of 4,
556 // and set the bits. So probably we want to convert this HBITMAP into a
557 // DIB, then call SetDIBits.
558 // AAAGH. The stupid thing is that if newBitmap has a depth of 4 (less than that of
559 // the screen), then SetDIBits fails.
560 HBITMAP newBitmap = ::CreateBitmap(totalBitmapWidth, totalBitmapHeight, 1, 4, NULL);
561 HANDLE newDIB = ::BitmapToDIB((HBITMAP) m_hBitmap, NULL);
562 LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) GlobalLock(newDIB);
563
564 dc = ::GetDC(NULL);
565 // LPBITMAPINFOHEADER lpbmi = (LPBITMAPINFOHEADER) newDIB;
566
567 int result = ::SetDIBits(dc, newBitmap, 0, lpbmi->biHeight, FindDIBBits((LPSTR)lpbmi), (LPBITMAPINFO)lpbmi,
568 DIB_PAL_COLORS);
569 DWORD err = GetLastError();
570
571 ::ReleaseDC(NULL, dc);
572
573 // Delete the DIB
574 GlobalUnlock (newDIB);
575 GlobalFree (newDIB);
576
577 // WXHBITMAP hBitmap2 = wxCreateMappedBitmap((WXHINSTANCE) wxGetInstance(), (WXHBITMAP) m_hBitmap);
578 // Substitute our new bitmap for the old one
579 ::DeleteObject((HBITMAP) m_hBitmap);
580 m_hBitmap = (WXHBITMAP) newBitmap;
581 #endif
582
583
584 #endif