]> git.saurik.com Git - wxWidgets.git/blob - src/common/tbarbase.cpp
fixing focus handling for generic controls in carbon-cfm
[wxWidgets.git] / src / common / tbarbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/tbarbase.cpp
3 // Purpose: wxToolBarBase implementation
4 // Author: Julian Smart
5 // Modified by: VZ at 11.12.99 (wxScrollableToolBar split off)
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
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 #if wxUSE_TOOLBAR
28
29 #ifndef WX_PRECOMP
30 #include "wx/control.h"
31 #endif
32
33 #include "wx/frame.h"
34
35 #if wxUSE_IMAGE
36 #include "wx/image.h"
37 #include "wx/settings.h"
38 #endif // wxUSE_IMAGE
39
40 #include "wx/toolbar.h"
41
42 // ----------------------------------------------------------------------------
43 // wxWidgets macros
44 // ----------------------------------------------------------------------------
45
46 BEGIN_EVENT_TABLE(wxToolBarBase, wxControl)
47 END_EVENT_TABLE()
48
49 #include "wx/listimpl.cpp"
50
51 WX_DEFINE_LIST(wxToolBarToolsList)
52
53 // ============================================================================
54 // implementation
55 // ============================================================================
56
57 // ----------------------------------------------------------------------------
58 // wxToolBarToolBase
59 // ----------------------------------------------------------------------------
60
61 IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject)
62
63 bool wxToolBarToolBase::Enable(bool enable)
64 {
65 if ( m_enabled == enable )
66 return false;
67
68 m_enabled = enable;
69
70 return true;
71 }
72
73 bool wxToolBarToolBase::Toggle(bool toggle)
74 {
75 wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") );
76
77 if ( m_toggled == toggle )
78 return false;
79
80 m_toggled = toggle;
81
82 return true;
83 }
84
85 bool wxToolBarToolBase::SetToggle(bool toggle)
86 {
87 wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL;
88 if ( m_kind == kind )
89 return false;
90
91 m_kind = kind;
92
93 return true;
94 }
95
96 bool wxToolBarToolBase::SetShortHelp(const wxString& help)
97 {
98 if ( m_shortHelpString == help )
99 return false;
100
101 m_shortHelpString = help;
102
103 return true;
104 }
105
106 bool wxToolBarToolBase::SetLongHelp(const wxString& help)
107 {
108 if ( m_longHelpString == help )
109 return false;
110
111 m_longHelpString = help;
112
113 return true;
114 }
115
116 #if WXWIN_COMPATIBILITY_2_2
117
118 const wxBitmap& wxToolBarToolBase::GetBitmap1() const
119 {
120 return GetNormalBitmap();
121 }
122
123 const wxBitmap& wxToolBarToolBase::GetBitmap2() const
124 {
125 return GetDisabledBitmap();
126 }
127
128 void wxToolBarToolBase::SetBitmap1(const wxBitmap& bmp)
129 {
130 SetNormalBitmap(bmp);
131 }
132
133 void wxToolBarToolBase::SetBitmap2(const wxBitmap& bmp)
134 {
135 SetDisabledBitmap(bmp);
136 }
137
138 #endif // WXWIN_COMPATIBILITY_2_2
139
140 // ----------------------------------------------------------------------------
141 // wxToolBarBase adding/deleting items
142 // ----------------------------------------------------------------------------
143
144 wxToolBarBase::wxToolBarBase()
145 {
146 // the list owns the pointers
147 m_xMargin = m_yMargin = 0;
148 m_maxRows = m_maxCols = 0;
149 m_toolPacking = m_toolSeparation = 0;
150 m_defaultWidth = 16;
151 m_defaultHeight = 15;
152 }
153
154 wxToolBarToolBase *wxToolBarBase::DoAddTool(int id,
155 const wxString& label,
156 const wxBitmap& bitmap,
157 const wxBitmap& bmpDisabled,
158 wxItemKind kind,
159 const wxString& shortHelp,
160 const wxString& longHelp,
161 wxObject *clientData,
162 wxCoord WXUNUSED(xPos),
163 wxCoord WXUNUSED(yPos))
164 {
165 InvalidateBestSize();
166 return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled,
167 kind, shortHelp, longHelp, clientData);
168 }
169
170 wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos,
171 int id,
172 const wxString& label,
173 const wxBitmap& bitmap,
174 const wxBitmap& bmpDisabled,
175 wxItemKind kind,
176 const wxString& shortHelp,
177 const wxString& longHelp,
178 wxObject *clientData)
179 {
180 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
181 _T("invalid position in wxToolBar::InsertTool()") );
182
183 wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind,
184 clientData, shortHelp, longHelp);
185
186 if ( !InsertTool(pos, tool) )
187 {
188 delete tool;
189
190 return NULL;
191 }
192
193 return tool;
194 }
195
196 wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool)
197 {
198 return InsertTool(GetToolsCount(), tool);
199 }
200
201 wxToolBarToolBase *
202 wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool)
203 {
204 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
205 _T("invalid position in wxToolBar::InsertTool()") );
206
207 if ( !tool || !DoInsertTool(pos, tool) )
208 {
209 return NULL;
210 }
211
212 m_tools.Insert(pos, tool);
213
214 return tool;
215 }
216
217 wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control)
218 {
219 return InsertControl(GetToolsCount(), control);
220 }
221
222 wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control)
223 {
224 wxCHECK_MSG( control, (wxToolBarToolBase *)NULL,
225 _T("toolbar: can't insert NULL control") );
226
227 wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL,
228 _T("control must have toolbar as parent") );
229
230 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
231 _T("invalid position in wxToolBar::InsertControl()") );
232
233 wxToolBarToolBase *tool = CreateTool(control);
234
235 if ( !InsertTool(pos, tool) )
236 {
237 delete tool;
238
239 return NULL;
240 }
241
242 return tool;
243 }
244
245 wxControl *wxToolBarBase::FindControl( int id )
246 {
247 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
248 node;
249 node = node->GetNext() )
250 {
251 const wxToolBarToolBase * const tool = node->GetData();
252 if ( tool->IsControl() )
253 {
254 wxControl * const control = tool->GetControl();
255
256 if ( !control )
257 {
258 wxFAIL_MSG( _T("NULL control in toolbar?") );
259 }
260 else if ( control->GetId() == id )
261 {
262 // found
263 return control;
264 }
265 }
266 }
267
268 return NULL;
269 }
270
271 wxToolBarToolBase *wxToolBarBase::AddSeparator()
272 {
273 return InsertSeparator(GetToolsCount());
274 }
275
276 wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos)
277 {
278 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL,
279 _T("invalid position in wxToolBar::InsertSeparator()") );
280
281 wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR,
282 wxEmptyString,
283 wxNullBitmap, wxNullBitmap,
284 wxITEM_SEPARATOR, (wxObject *)NULL,
285 wxEmptyString, wxEmptyString);
286
287 if ( !tool || !DoInsertTool(pos, tool) )
288 {
289 delete tool;
290
291 return NULL;
292 }
293
294 m_tools.Insert(pos, tool);
295
296 return tool;
297 }
298
299 wxToolBarToolBase *wxToolBarBase::RemoveTool(int id)
300 {
301 size_t pos = 0;
302 wxToolBarToolsList::compatibility_iterator node;
303 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
304 {
305 if ( node->GetData()->GetId() == id )
306 break;
307
308 pos++;
309 }
310
311 if ( !node )
312 {
313 // don't give any error messages - sometimes we might call RemoveTool()
314 // without knowing whether the tool is or not in the toolbar
315 return (wxToolBarToolBase *)NULL;
316 }
317
318 wxToolBarToolBase *tool = node->GetData();
319 if ( !DoDeleteTool(pos, tool) )
320 {
321 return (wxToolBarToolBase *)NULL;
322 }
323
324 m_tools.Erase(node);
325
326 return tool;
327 }
328
329 bool wxToolBarBase::DeleteToolByPos(size_t pos)
330 {
331 wxCHECK_MSG( pos < GetToolsCount(), false,
332 _T("invalid position in wxToolBar::DeleteToolByPos()") );
333
334 wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos);
335
336 if ( !DoDeleteTool(pos, node->GetData()) )
337 {
338 return false;
339 }
340
341 delete node->GetData();
342 m_tools.Erase(node);
343
344 return true;
345 }
346
347 bool wxToolBarBase::DeleteTool(int id)
348 {
349 size_t pos = 0;
350 wxToolBarToolsList::compatibility_iterator node;
351 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
352 {
353 if ( node->GetData()->GetId() == id )
354 break;
355
356 pos++;
357 }
358
359 if ( !node || !DoDeleteTool(pos, node->GetData()) )
360 {
361 return false;
362 }
363
364 delete node->GetData();
365 m_tools.Erase(node);
366
367 return true;
368 }
369
370 wxToolBarToolBase *wxToolBarBase::FindById(int id) const
371 {
372 wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL;
373
374 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
375 node;
376 node = node->GetNext() )
377 {
378 tool = node->GetData();
379 if ( tool->GetId() == id )
380 {
381 // found
382 break;
383 }
384
385 tool = NULL;
386 }
387
388 return tool;
389 }
390
391 void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool)
392 {
393 wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") );
394
395 if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO )
396 return;
397
398 wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool);
399 wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") );
400
401 wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext();
402 while ( nodeNext )
403 {
404 wxToolBarToolBase *toolNext = nodeNext->GetData();
405
406 if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO )
407 break;
408
409 if ( toolNext->Toggle(false) )
410 {
411 DoToggleTool(toolNext, false);
412 }
413
414 nodeNext = nodeNext->GetNext();
415 }
416
417 wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious();
418 while ( nodePrev )
419 {
420 wxToolBarToolBase *toolNext = nodePrev->GetData();
421
422 if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO )
423 break;
424
425 if ( toolNext->Toggle(false) )
426 {
427 DoToggleTool(toolNext, false);
428 }
429
430 nodePrev = nodePrev->GetPrevious();
431 }
432 }
433
434 void wxToolBarBase::ClearTools()
435 {
436 WX_CLEAR_LIST(wxToolBarToolsList, m_tools);
437 }
438
439 bool wxToolBarBase::Realize()
440 {
441 return true;
442 }
443
444 wxToolBarBase::~wxToolBarBase()
445 {
446 WX_CLEAR_LIST(wxToolBarToolsList, m_tools);
447
448 // notify the frame that it doesn't have a tool bar any longer to avoid
449 // dangling pointers
450 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
451 if ( frame && frame->GetToolBar() == this )
452 {
453 frame->SetToolBar(NULL);
454 }
455 }
456
457 // ----------------------------------------------------------------------------
458 // wxToolBarBase tools state
459 // ----------------------------------------------------------------------------
460
461 void wxToolBarBase::EnableTool(int id, bool enable)
462 {
463 wxToolBarToolBase *tool = FindById(id);
464 if ( tool )
465 {
466 if ( tool->Enable(enable) )
467 {
468 DoEnableTool(tool, enable);
469 }
470 }
471 }
472
473 void wxToolBarBase::ToggleTool(int id, bool toggle)
474 {
475 wxToolBarToolBase *tool = FindById(id);
476 if ( tool && tool->CanBeToggled() )
477 {
478 if ( tool->Toggle(toggle) )
479 {
480 UnToggleRadioGroup(tool);
481 DoToggleTool(tool, toggle);
482 }
483 }
484 }
485
486 void wxToolBarBase::SetToggle(int id, bool toggle)
487 {
488 wxToolBarToolBase *tool = FindById(id);
489 if ( tool )
490 {
491 if ( tool->SetToggle(toggle) )
492 {
493 DoSetToggle(tool, toggle);
494 }
495 }
496 }
497
498 void wxToolBarBase::SetToolShortHelp(int id, const wxString& help)
499 {
500 wxToolBarToolBase *tool = FindById(id);
501 if ( tool )
502 {
503 (void)tool->SetShortHelp(help);
504 }
505 }
506
507 void wxToolBarBase::SetToolLongHelp(int id, const wxString& help)
508 {
509 wxToolBarToolBase *tool = FindById(id);
510 if ( tool )
511 {
512 (void)tool->SetLongHelp(help);
513 }
514 }
515
516 wxObject *wxToolBarBase::GetToolClientData(int id) const
517 {
518 wxToolBarToolBase *tool = FindById(id);
519
520 return tool ? tool->GetClientData() : (wxObject *)NULL;
521 }
522
523 void wxToolBarBase::SetToolClientData(int id, wxObject *clientData)
524 {
525 wxToolBarToolBase *tool = FindById(id);
526
527 wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") );
528
529 tool->SetClientData(clientData);
530 }
531
532 int wxToolBarBase::GetToolPos(int id) const
533 {
534 size_t pos = 0;
535 wxToolBarToolsList::compatibility_iterator node;
536
537 for ( node = m_tools.GetFirst(); node; node = node->GetNext() )
538 {
539 if ( node->GetData()->GetId() == id )
540 return pos;
541
542 pos++;
543 }
544
545 return wxNOT_FOUND;
546 }
547
548 bool wxToolBarBase::GetToolState(int id) const
549 {
550 wxToolBarToolBase *tool = FindById(id);
551 wxCHECK_MSG( tool, false, _T("no such tool") );
552
553 return tool->IsToggled();
554 }
555
556 bool wxToolBarBase::GetToolEnabled(int id) const
557 {
558 wxToolBarToolBase *tool = FindById(id);
559 wxCHECK_MSG( tool, false, _T("no such tool") );
560
561 return tool->IsEnabled();
562 }
563
564 wxString wxToolBarBase::GetToolShortHelp(int id) const
565 {
566 wxToolBarToolBase *tool = FindById(id);
567 wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") );
568
569 return tool->GetShortHelp();
570 }
571
572 wxString wxToolBarBase::GetToolLongHelp(int id) const
573 {
574 wxToolBarToolBase *tool = FindById(id);
575 wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") );
576
577 return tool->GetLongHelp();
578 }
579
580 // ----------------------------------------------------------------------------
581 // wxToolBarBase geometry
582 // ----------------------------------------------------------------------------
583
584 void wxToolBarBase::SetMargins(int x, int y)
585 {
586 m_xMargin = x;
587 m_yMargin = y;
588 }
589
590 void wxToolBarBase::SetRows(int WXUNUSED(nRows))
591 {
592 // nothing
593 }
594
595 // ----------------------------------------------------------------------------
596 // event processing
597 // ----------------------------------------------------------------------------
598
599 // Only allow toggle if returns true
600 bool wxToolBarBase::OnLeftClick(int id, bool toggleDown)
601 {
602 wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id);
603 event.SetEventObject(this);
604
605 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
606 event.SetInt((int)toggleDown);
607
608 // and SetExtraLong() for backwards compatibility
609 event.SetExtraLong((long)toggleDown);
610
611 // Send events to this toolbar instead (and thence up the window hierarchy)
612 GetEventHandler()->ProcessEvent(event);
613
614 return true;
615 }
616
617 // Call when right button down.
618 void wxToolBarBase::OnRightClick(int id,
619 long WXUNUSED(x),
620 long WXUNUSED(y))
621 {
622 wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id);
623 event.SetEventObject(this);
624 event.SetInt(id);
625
626 GetEventHandler()->ProcessEvent(event);
627 }
628
629 // Called when the mouse cursor enters a tool bitmap (no button pressed).
630 // Argument is wxID_ANY if mouse is exiting the toolbar.
631 // Note that for this event, the id of the window is used,
632 // and the integer parameter of wxCommandEvent is used to retrieve
633 // the tool id.
634 void wxToolBarBase::OnMouseEnter(int id)
635 {
636 wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId());
637 event.SetEventObject(this);
638 event.SetInt(id);
639
640 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame);
641 if( frame )
642 {
643 wxString help;
644 wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id);
645 if(tool)
646 help = tool->GetLongHelp();
647 frame->DoGiveHelp( help, id != wxID_ANY );
648 }
649
650 (void)GetEventHandler()->ProcessEvent(event);
651 }
652
653 // ----------------------------------------------------------------------------
654 // UI updates
655 // ----------------------------------------------------------------------------
656
657 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
658 void wxToolBarBase::UpdateWindowUI(long flags)
659 {
660 wxWindowBase::UpdateWindowUI(flags);
661
662 // There is no sense in updating the toolbar UI
663 // if the parent window is about to get destroyed
664 wxWindow *tlw = wxGetTopLevelParent( this );
665 if (tlw && wxPendingDelete.Member( tlw ))
666 return;
667
668 wxEvtHandler* evtHandler = GetEventHandler() ;
669
670 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst();
671 node;
672 node = node->GetNext() )
673 {
674 int id = node->GetData()->GetId();
675
676 wxUpdateUIEvent event(id);
677 event.SetEventObject(this);
678
679 if ( evtHandler->ProcessEvent(event) )
680 {
681 if ( event.GetSetEnabled() )
682 EnableTool(id, event.GetEnabled());
683 if ( event.GetSetChecked() )
684 ToggleTool(id, event.GetChecked());
685 #if 0
686 if ( event.GetSetText() )
687 // Set tooltip?
688 #endif // 0
689 }
690 }
691 }
692
693 #if wxUSE_IMAGE
694
695 /*
696 * Make a greyed-out image suitable for disabled buttons.
697 * This code is adapted from wxNewBitmapButton in FL.
698 */
699
700 bool wxCreateGreyedImage(const wxImage& src, wxImage& dst)
701 {
702 dst = src.Copy();
703
704 unsigned char rBg, gBg, bBg;
705 if ( src.HasMask() )
706 {
707 src.GetOrFindMaskColour(&rBg, &gBg, &bBg);
708 dst.SetMaskColour(rBg, gBg, bBg);
709 }
710 else // assuming the pixels along the edges are of the background color
711 {
712 rBg = src.GetRed(0, 0);
713 gBg = src.GetGreen(0, 0);
714 bBg = src.GetBlue(0, 0);
715 }
716
717 const wxColour colBg(rBg, gBg, bBg);
718
719 const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW);
720 const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT);
721
722 // Second attempt, just making things monochrome
723 const int width = src.GetWidth();
724 const int height = src.GetHeight();
725
726 for ( int x = 0; x < width; x++ )
727 {
728 for ( int y = 0; y < height; y++ )
729 {
730 const int r = src.GetRed(x, y);
731 const int g = src.GetGreen(x, y);
732 const int b = src.GetBlue(x, y);
733
734 if ( r == rBg && g == gBg && b == bBg )
735 {
736 // Leave the background colour as-is
737 continue;
738 }
739
740 // Change light things to the background colour
741 wxColour col;
742 if ( r >= (colLight.Red() - 50) &&
743 g >= (colLight.Green() - 50) &&
744 b >= (colLight.Blue() - 50) )
745 {
746 col = colBg;
747 }
748 else // Change dark things to really dark
749 {
750 col = colDark;
751 }
752
753 dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue());
754 }
755 }
756
757 return true;
758 }
759
760 #endif // wxUSE_IMAGE
761
762 #endif // wxUSE_TOOLBAR