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