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