]>
Commit | Line | Data |
---|---|---|
1 | ///////////////////////////////////////////////////////////////////////////// | |
2 | // Name: src/generic/buttonbar.cpp | |
3 | // Purpose: wxButtonToolBar implementation | |
4 | // Author: Julian Smart, after Robert Roebling, Vadim Zeitlin, SciTech | |
5 | // Modified by: | |
6 | // Created: 2006-04-13 | |
7 | // Copyright: (c) Julian Smart, Robert Roebling, Vadim Zeitlin, | |
8 | // SciTech Software, Inc. | |
9 | // Licence: wxWindows licence | |
10 | ///////////////////////////////////////////////////////////////////////////// | |
11 | ||
12 | // ============================================================================ | |
13 | // declarations | |
14 | // ============================================================================ | |
15 | ||
16 | // ---------------------------------------------------------------------------- | |
17 | // headers | |
18 | // ---------------------------------------------------------------------------- | |
19 | ||
20 | // For compilers that support precompilation, includes "wx.h". | |
21 | #include "wx/wxprec.h" | |
22 | ||
23 | #ifdef __BORLANDC__ | |
24 | #pragma hdrstop | |
25 | #endif | |
26 | ||
27 | // Currently, only for Mac as a toolbar replacement. | |
28 | #if defined(__WXMAC__) && wxUSE_TOOLBAR && wxUSE_BMPBUTTON | |
29 | ||
30 | #include "wx/generic/buttonbar.h" | |
31 | ||
32 | #ifndef WX_PRECOMP | |
33 | #include "wx/utils.h" | |
34 | #include "wx/app.h" | |
35 | #include "wx/log.h" | |
36 | #include "wx/frame.h" | |
37 | #include "wx/dcclient.h" | |
38 | #include "wx/settings.h" | |
39 | #include "wx/image.h" | |
40 | #endif | |
41 | ||
42 | // ---------------------------------------------------------------------------- | |
43 | // wxButtonToolBarTool: our implementation of wxToolBarToolBase | |
44 | // ---------------------------------------------------------------------------- | |
45 | ||
46 | class WXDLLEXPORT wxButtonToolBarTool : public wxToolBarToolBase | |
47 | { | |
48 | public: | |
49 | wxButtonToolBarTool(wxButtonToolBar *tbar, | |
50 | int id, | |
51 | const wxString& label, | |
52 | const wxBitmap& bmpNormal, | |
53 | const wxBitmap& bmpDisabled, | |
54 | wxItemKind kind, | |
55 | wxObject *clientData, | |
56 | const wxString& shortHelp, | |
57 | const wxString& longHelp) | |
58 | : wxToolBarToolBase(tbar, id, label, bmpNormal, bmpDisabled, kind, | |
59 | clientData, shortHelp, longHelp) | |
60 | { | |
61 | m_x = m_y = wxDefaultCoord; | |
62 | m_width = | |
63 | m_height = 0; | |
64 | ||
65 | m_button = NULL; | |
66 | } | |
67 | ||
68 | wxButtonToolBarTool(wxButtonToolBar *tbar, | |
69 | wxControl *control, | |
70 | const wxString& label) | |
71 | : wxToolBarToolBase(tbar, control, label) | |
72 | { | |
73 | m_x = m_y = wxDefaultCoord; | |
74 | m_width = | |
75 | m_height = 0; | |
76 | m_button = NULL; | |
77 | } | |
78 | ||
79 | wxBitmapButton* GetButton() const { return m_button; } | |
80 | void SetButton(wxBitmapButton* button) { m_button = button; } | |
81 | ||
82 | public: | |
83 | // the tool position (for controls) | |
84 | wxCoord m_x; | |
85 | wxCoord m_y; | |
86 | wxCoord m_width; | |
87 | wxCoord m_height; | |
88 | ||
89 | private: | |
90 | // the control representing the button | |
91 | wxBitmapButton* m_button; | |
92 | }; | |
93 | ||
94 | // ============================================================================ | |
95 | // wxButtonToolBar implementation | |
96 | // ============================================================================ | |
97 | ||
98 | IMPLEMENT_DYNAMIC_CLASS(wxButtonToolBar, wxControl) | |
99 | ||
100 | BEGIN_EVENT_TABLE(wxButtonToolBar, wxControl) | |
101 | EVT_BUTTON(wxID_ANY, wxButtonToolBar::OnCommand) | |
102 | EVT_PAINT(wxButtonToolBar::OnPaint) | |
103 | EVT_LEFT_UP(wxButtonToolBar::OnLeftUp) | |
104 | END_EVENT_TABLE() | |
105 | ||
106 | // ---------------------------------------------------------------------------- | |
107 | // wxButtonToolBar creation | |
108 | // ---------------------------------------------------------------------------- | |
109 | ||
110 | void wxButtonToolBar::Init() | |
111 | { | |
112 | // no tools yet | |
113 | m_needsLayout = false; | |
114 | ||
115 | // unknown widths for the tools and separators | |
116 | m_widthSeparator = wxDefaultCoord; | |
117 | ||
118 | m_maxWidth = m_maxHeight = 0; | |
119 | ||
120 | m_labelMargin = 2; | |
121 | m_labelHeight = 0; | |
122 | ||
123 | SetMargins(8, 2); | |
124 | SetToolPacking(8); | |
125 | } | |
126 | ||
127 | bool wxButtonToolBar::Create(wxWindow *parent, | |
128 | wxWindowID id, | |
129 | const wxPoint& pos, | |
130 | const wxSize& size, | |
131 | long style, | |
132 | const wxString& name) | |
133 | { | |
134 | if ( !wxToolBarBase::Create(parent, id, pos, size, style, | |
135 | wxDefaultValidator, name) ) | |
136 | { | |
137 | return false; | |
138 | } | |
139 | ||
140 | // wxColour lightBackground(244, 244, 244); | |
141 | ||
142 | wxFont font(wxSMALL_FONT->GetPointSize(), | |
143 | wxNORMAL_FONT->GetFamily(), | |
144 | wxNORMAL_FONT->GetStyle(), | |
145 | wxFONTWEIGHT_NORMAL); | |
146 | SetFont(font); | |
147 | ||
148 | // Calculate the label height if necessary | |
149 | if (GetWindowStyle() & wxTB_TEXT) | |
150 | { | |
151 | wxClientDC dc(this); | |
152 | dc.SetFont(font); | |
153 | int w, h; | |
154 | dc.GetTextExtent(wxT("X"), & w, & h); | |
155 | m_labelHeight = h; | |
156 | } | |
157 | return true; | |
158 | } | |
159 | ||
160 | wxButtonToolBar::~wxButtonToolBar() | |
161 | { | |
162 | } | |
163 | ||
164 | // ---------------------------------------------------------------------------- | |
165 | // wxButtonToolBar tool-related methods | |
166 | // ---------------------------------------------------------------------------- | |
167 | ||
168 | wxToolBarToolBase *wxButtonToolBar::FindToolForPosition(wxCoord x, wxCoord y) const | |
169 | { | |
170 | // check the "other" direction first: it must be inside the toolbar or we | |
171 | // don't risk finding anything | |
172 | if ( IsVertical() ) | |
173 | { | |
174 | if ( x < 0 || x > m_maxWidth ) | |
175 | return NULL; | |
176 | ||
177 | // we always use x, even for a vertical toolbar, this makes the code | |
178 | // below simpler | |
179 | x = y; | |
180 | } | |
181 | else // horizontal | |
182 | { | |
183 | if ( y < 0 || y > m_maxHeight ) | |
184 | return NULL; | |
185 | } | |
186 | ||
187 | for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); | |
188 | node; | |
189 | node = node->GetNext() ) | |
190 | { | |
191 | wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); | |
192 | wxRect rectTool = GetToolRect(tool); | |
193 | ||
194 | wxCoord startTool, endTool; | |
195 | GetRectLimits(rectTool, &startTool, &endTool); | |
196 | ||
197 | if ( x >= startTool && x <= endTool ) | |
198 | { | |
199 | // don't return the separators from here, they don't accept any | |
200 | // input anyhow | |
201 | return tool->IsSeparator() ? NULL : tool; | |
202 | } | |
203 | } | |
204 | ||
205 | return NULL; | |
206 | } | |
207 | ||
208 | void wxButtonToolBar::GetRectLimits(const wxRect& rect, | |
209 | wxCoord *start, | |
210 | wxCoord *end) const | |
211 | { | |
212 | wxCHECK_RET( start && end, wxT("NULL pointer in GetRectLimits") ); | |
213 | ||
214 | if ( IsVertical() ) | |
215 | { | |
216 | *start = rect.GetTop(); | |
217 | *end = rect.GetBottom(); | |
218 | } | |
219 | else // horizontal | |
220 | { | |
221 | *start = rect.GetLeft(); | |
222 | *end = rect.GetRight(); | |
223 | } | |
224 | } | |
225 | ||
226 | ||
227 | void wxButtonToolBar::SetToolShortHelp(int id, const wxString& help) | |
228 | { | |
229 | wxToolBarToolBase *tool = FindById(id); | |
230 | ||
231 | wxCHECK_RET( tool, wxT("SetToolShortHelp: no such tool") ); | |
232 | ||
233 | // TODO: set tooltip/short help | |
234 | tool->SetShortHelp(help); | |
235 | } | |
236 | ||
237 | bool wxButtonToolBar::DoInsertTool(size_t WXUNUSED(pos), | |
238 | wxToolBarToolBase * WXUNUSED(tool)) | |
239 | { | |
240 | return true; | |
241 | } | |
242 | ||
243 | bool wxButtonToolBar::DoDeleteTool(size_t WXUNUSED(pos), | |
244 | wxToolBarToolBase * WXUNUSED(tool)) | |
245 | { | |
246 | // TODO | |
247 | return true; | |
248 | } | |
249 | ||
250 | void wxButtonToolBar::DoEnableTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(enable)) | |
251 | { | |
252 | // TODO | |
253 | } | |
254 | ||
255 | void wxButtonToolBar::DoToggleTool(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) | |
256 | { | |
257 | // TODO | |
258 | } | |
259 | ||
260 | void wxButtonToolBar::DoSetToggle(wxToolBarToolBase *WXUNUSED(tool), bool WXUNUSED(toggle)) | |
261 | { | |
262 | // TODO | |
263 | } | |
264 | ||
265 | wxToolBarToolBase *wxButtonToolBar::CreateTool(int id, | |
266 | const wxString& label, | |
267 | const wxBitmap& bmpNormal, | |
268 | const wxBitmap& bmpDisabled, | |
269 | wxItemKind kind, | |
270 | wxObject *clientData, | |
271 | const wxString& shortHelp, | |
272 | const wxString& longHelp) | |
273 | { | |
274 | return new wxButtonToolBarTool(this, id, label, bmpNormal, bmpDisabled, kind, | |
275 | clientData, shortHelp, longHelp); | |
276 | } | |
277 | ||
278 | wxToolBarToolBase *wxButtonToolBar::CreateTool(wxControl *control, | |
279 | const wxString& label) | |
280 | { | |
281 | return new wxButtonToolBarTool(this, control, label); | |
282 | } | |
283 | ||
284 | // ---------------------------------------------------------------------------- | |
285 | // wxButtonToolBar geometry | |
286 | // ---------------------------------------------------------------------------- | |
287 | ||
288 | wxRect wxButtonToolBar::GetToolRect(wxToolBarToolBase *toolBase) const | |
289 | { | |
290 | const wxButtonToolBarTool *tool = (wxButtonToolBarTool *)toolBase; | |
291 | ||
292 | wxRect rect; | |
293 | ||
294 | wxCHECK_MSG( tool, rect, wxT("GetToolRect: NULL tool") ); | |
295 | ||
296 | // ensure that we always have the valid tool position | |
297 | if ( m_needsLayout ) | |
298 | { | |
299 | wxConstCast(this, wxButtonToolBar)->DoLayout(); | |
300 | } | |
301 | ||
302 | rect.x = tool->m_x - (m_toolPacking/2); | |
303 | rect.y = tool->m_y; | |
304 | ||
305 | if ( IsVertical() ) | |
306 | { | |
307 | if (tool->IsButton()) | |
308 | { | |
309 | rect.width = m_defaultWidth; | |
310 | rect.height = m_defaultHeight; | |
311 | if (tool->GetButton()) | |
312 | rect.SetSize(wxSize(tool->m_width, tool->m_height)); | |
313 | } | |
314 | else if (tool->IsSeparator()) | |
315 | { | |
316 | rect.width = m_defaultWidth; | |
317 | rect.height = m_widthSeparator; | |
318 | } | |
319 | else // control | |
320 | { | |
321 | rect.width = tool->m_width; | |
322 | rect.height = tool->m_height; | |
323 | } | |
324 | } | |
325 | else // horizontal | |
326 | { | |
327 | if (tool->IsButton()) | |
328 | { | |
329 | rect.width = m_defaultWidth; | |
330 | rect.height = m_defaultHeight; | |
331 | if (tool->GetButton()) | |
332 | rect.SetSize(wxSize(tool->m_width, tool->m_height)); | |
333 | } | |
334 | else if (tool->IsSeparator()) | |
335 | { | |
336 | rect.width = m_widthSeparator; | |
337 | rect.height = m_defaultHeight; | |
338 | } | |
339 | else // control | |
340 | { | |
341 | rect.width = tool->m_width; | |
342 | rect.height = tool->m_height; | |
343 | } | |
344 | } | |
345 | ||
346 | rect.width += m_toolPacking; | |
347 | ||
348 | return rect; | |
349 | } | |
350 | ||
351 | bool wxButtonToolBar::Realize() | |
352 | { | |
353 | if ( !wxToolBarBase::Realize() ) | |
354 | return false; | |
355 | ||
356 | m_needsLayout = true; | |
357 | DoLayout(); | |
358 | ||
359 | SetInitialSize(wxSize(m_maxWidth, m_maxHeight)); | |
360 | ||
361 | return true; | |
362 | } | |
363 | ||
364 | void wxButtonToolBar::DoLayout() | |
365 | { | |
366 | m_needsLayout = false; | |
367 | ||
368 | wxCoord x = m_xMargin, | |
369 | y = m_yMargin; | |
370 | ||
371 | int maxHeight = 0; | |
372 | ||
373 | const wxCoord widthTool = IsVertical() ? m_defaultHeight : m_defaultWidth; | |
374 | wxCoord margin = IsVertical() ? m_xMargin : m_yMargin; | |
375 | wxCoord *pCur = IsVertical() ? &y : &x; | |
376 | ||
377 | // calculate the positions of all elements | |
378 | for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); | |
379 | node; | |
380 | node = node->GetNext() ) | |
381 | { | |
382 | wxButtonToolBarTool *tool = (wxButtonToolBarTool *) node->GetData(); | |
383 | ||
384 | tool->m_x = x; | |
385 | tool->m_y = y; | |
386 | ||
387 | if (tool->IsButton()) | |
388 | { | |
389 | if (!tool->GetButton()) | |
390 | { | |
391 | wxBitmapButton* bmpButton = new wxBitmapButton(this, tool->GetId(), tool->GetNormalBitmap(), wxPoint(tool->m_x, tool->m_y), wxDefaultSize, | |
392 | wxBU_AUTODRAW|wxBORDER_NONE); | |
393 | if (!tool->GetShortHelp().empty()) | |
394 | bmpButton->SetLabel(tool->GetShortHelp()); | |
395 | ||
396 | tool->SetButton(bmpButton); | |
397 | } | |
398 | else | |
399 | { | |
400 | tool->GetButton()->Move(wxPoint(tool->m_x, tool->m_y)); | |
401 | } | |
402 | ||
403 | int w = widthTool; | |
404 | if (tool->GetButton()) | |
405 | { | |
406 | wxSize sz = tool->GetButton()->GetSize(); | |
407 | w = sz.x; | |
408 | ||
409 | if (m_labelHeight > 0) | |
410 | { | |
411 | sz.y += (m_labelHeight + m_labelMargin); | |
412 | ||
413 | if (!tool->GetShortHelp().empty()) | |
414 | { | |
415 | wxClientDC dc(this); | |
416 | dc.SetFont(GetFont()); | |
417 | int tw, th; | |
418 | dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); | |
419 | ||
420 | // If the label is bigger than the icon, the label width | |
421 | // becomes the new tool width, and we need to centre the | |
422 | // the bitmap in this box. | |
423 | if (tw > sz.x) | |
424 | { | |
425 | int newX = int(tool->m_x + (tw - sz.x)/2.0); | |
426 | tool->GetButton()->Move(newX, tool->m_y); | |
427 | sz.x = tw; | |
428 | } | |
429 | } | |
430 | } | |
431 | ||
432 | maxHeight = wxMax(maxHeight, sz.y); | |
433 | ||
434 | tool->m_width = sz.x; | |
435 | tool->m_height = sz.y; | |
436 | w = sz.x; | |
437 | } | |
438 | ||
439 | *pCur += (w + GetToolPacking()); | |
440 | } | |
441 | else if (tool->IsSeparator()) | |
442 | { | |
443 | *pCur += m_widthSeparator; | |
444 | } | |
445 | else if (!IsVertical()) // horizontal control | |
446 | { | |
447 | wxControl *control = tool->GetControl(); | |
448 | wxSize size = control->GetSize(); | |
449 | tool->m_y += (m_defaultHeight - size.y)/2; | |
450 | tool->m_width = size.x; | |
451 | tool->m_height = size.y; | |
452 | ||
453 | *pCur += tool->m_width; | |
454 | ||
455 | maxHeight = wxMax(maxHeight, size.y); | |
456 | } | |
457 | *pCur += margin; | |
458 | } | |
459 | ||
460 | // calculate the total toolbar size | |
461 | m_maxWidth = x + 2*m_xMargin; | |
462 | m_maxHeight = maxHeight + 2*m_yMargin; | |
463 | ||
464 | if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) | |
465 | m_maxHeight += 2; | |
466 | ||
467 | } | |
468 | ||
469 | wxSize wxButtonToolBar::DoGetBestClientSize() const | |
470 | { | |
471 | return wxSize(m_maxWidth, m_maxHeight); | |
472 | } | |
473 | ||
474 | // receives button commands | |
475 | void wxButtonToolBar::OnCommand(wxCommandEvent& event) | |
476 | { | |
477 | wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindById(event.GetId()); | |
478 | if (!tool) | |
479 | { | |
480 | event.Skip(); | |
481 | return; | |
482 | } | |
483 | ||
484 | if (tool->CanBeToggled()) | |
485 | tool->Toggle(tool->IsToggled()); | |
486 | ||
487 | // TODO: handle toggle items | |
488 | OnLeftClick(event.GetId(), false); | |
489 | ||
490 | if (tool->GetKind() == wxITEM_RADIO) | |
491 | UnToggleRadioGroup(tool); | |
492 | ||
493 | if (tool->CanBeToggled()) | |
494 | Refresh(); | |
495 | } | |
496 | ||
497 | // paints a border | |
498 | void wxButtonToolBar::OnPaint(wxPaintEvent& WXUNUSED(event)) | |
499 | { | |
500 | wxPaintDC dc(this); | |
501 | ||
502 | dc.SetFont(GetFont()); | |
503 | dc.SetBackgroundMode(wxTRANSPARENT); | |
504 | ||
505 | for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); | |
506 | node; | |
507 | node = node->GetNext() ) | |
508 | { | |
509 | wxButtonToolBarTool *tool = (wxButtonToolBarTool*) node->GetData(); | |
510 | wxRect rectTool = GetToolRect(tool); | |
511 | if (tool->IsToggled()) | |
512 | { | |
513 | wxRect backgroundRect = rectTool; | |
514 | backgroundRect.y = -1; backgroundRect.height = GetClientSize().y + 1; | |
515 | wxBrush brush(wxColour(219, 219, 219)); | |
516 | wxPen pen(wxColour(159, 159, 159)); | |
517 | dc.SetBrush(brush); | |
518 | dc.SetPen(pen); | |
519 | dc.DrawRectangle(backgroundRect); | |
520 | } | |
521 | ||
522 | if (m_labelHeight > 0 && !tool->GetShortHelp().empty()) | |
523 | { | |
524 | int tw, th; | |
525 | dc.GetTextExtent(tool->GetShortHelp(), & tw, & th); | |
526 | ||
527 | int x = tool->m_x; | |
528 | dc.DrawText(tool->GetShortHelp(), x, tool->m_y + tool->GetButton()->GetSize().y + m_labelMargin); | |
529 | } | |
530 | } | |
531 | ||
532 | if ((GetWindowStyle() & wxTB_NODIVIDER) == 0) | |
533 | { | |
534 | wxPen pen(wxColour(159, 159, 159)); | |
535 | dc.SetPen(pen); | |
536 | int x1 = 0; | |
537 | int y1 = GetClientSize().y-1; | |
538 | int x2 = GetClientSize().x; | |
539 | int y2 = y1; | |
540 | dc.DrawLine(x1, y1, x2, y2); | |
541 | } | |
542 | } | |
543 | ||
544 | // detects mouse clicks outside buttons | |
545 | void wxButtonToolBar::OnLeftUp(wxMouseEvent& event) | |
546 | { | |
547 | if (m_labelHeight > 0) | |
548 | { | |
549 | wxButtonToolBarTool* tool = (wxButtonToolBarTool*) FindToolForPosition(event.GetX(), event.GetY()); | |
550 | if (tool && tool->GetButton() && (event.GetY() > (tool->m_y + tool->GetButton()->GetSize().y))) | |
551 | { | |
552 | wxCommandEvent event(wxEVT_BUTTON, tool->GetId()); | |
553 | event.SetEventObject(tool->GetButton()); | |
554 | if (!GetEventHandler()->ProcessEvent(event)) | |
555 | event.Skip(); | |
556 | } | |
557 | } | |
558 | } | |
559 | ||
560 | #endif // wxUSE_TOOLBAR && wxUSE_BMPBUTTON |