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)
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
29 #include "wx/toolbar.h"
32 #include "wx/control.h"
34 #include "wx/settings.h"
35 #if WXWIN_COMPATIBILITY_2_8
37 #endif // WXWIN_COMPATIBILITY_2_8
41 extern WXDLLEXPORT_DATA(const char) wxToolBarNameStr
[] = "toolbar";
43 // ----------------------------------------------------------------------------
45 // ----------------------------------------------------------------------------
47 BEGIN_EVENT_TABLE(wxToolBarBase
, wxControl
)
50 #include "wx/listimpl.cpp"
52 WX_DEFINE_LIST(wxToolBarToolsList
)
54 // ============================================================================
56 // ============================================================================
58 // ----------------------------------------------------------------------------
60 // ----------------------------------------------------------------------------
62 IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase
, wxObject
)
64 wxToolBarToolBase::~wxToolBarToolBase()
67 delete m_dropdownMenu
;
71 GetControl()->Destroy();
75 bool wxToolBarToolBase::Enable(bool enable
)
77 if ( m_enabled
== enable
)
85 bool wxToolBarToolBase::Toggle(bool toggle
)
87 wxASSERT_MSG( CanBeToggled(), wxT("can't toggle this tool") );
89 if ( m_toggled
== toggle
)
97 bool wxToolBarToolBase::SetToggle(bool toggle
)
99 wxItemKind kind
= toggle
? wxITEM_CHECK
: wxITEM_NORMAL
;
100 if ( m_kind
== kind
)
108 bool wxToolBarToolBase::SetShortHelp(const wxString
& help
)
110 if ( m_shortHelpString
== help
)
113 m_shortHelpString
= help
;
118 bool wxToolBarToolBase::SetLongHelp(const wxString
& help
)
120 if ( m_longHelpString
== help
)
123 m_longHelpString
= help
;
130 void wxToolBarToolBase::SetDropdownMenu(wxMenu
* menu
)
132 delete m_dropdownMenu
;
133 m_dropdownMenu
= menu
;
138 // ----------------------------------------------------------------------------
139 // wxToolBarBase adding/deleting items
140 // ----------------------------------------------------------------------------
142 wxToolBarBase::wxToolBarBase()
144 // the list owns the pointers
145 m_xMargin
= m_yMargin
= 0;
146 m_maxRows
= m_maxCols
= 0;
147 m_toolPacking
= m_toolSeparation
= 0;
149 m_defaultHeight
= 15;
152 void wxToolBarBase::FixupStyle()
154 if ( !HasFlag(wxTB_TOP
| wxTB_LEFT
| wxTB_RIGHT
| wxTB_BOTTOM
) )
156 // this is the default
157 m_windowStyle
|= wxTB_TOP
;
161 wxToolBarToolBase
*wxToolBarBase::DoAddTool(int id
,
162 const wxString
& label
,
163 const wxBitmap
& bitmap
,
164 const wxBitmap
& bmpDisabled
,
166 const wxString
& shortHelp
,
167 const wxString
& longHelp
,
168 wxObject
*clientData
,
169 wxCoord
WXUNUSED(xPos
),
170 wxCoord
WXUNUSED(yPos
))
172 InvalidateBestSize();
173 return InsertTool(GetToolsCount(), id
, label
, bitmap
, bmpDisabled
,
174 kind
, shortHelp
, longHelp
, clientData
);
177 wxToolBarToolBase
*wxToolBarBase::InsertTool(size_t pos
,
179 const wxString
& label
,
180 const wxBitmap
& bitmap
,
181 const wxBitmap
& bmpDisabled
,
183 const wxString
& shortHelp
,
184 const wxString
& longHelp
,
185 wxObject
*clientData
)
187 wxCHECK_MSG( pos
<= GetToolsCount(), NULL
,
188 wxT("invalid position in wxToolBar::InsertTool()") );
190 return DoInsertNewTool(pos
, CreateTool(id
, label
, bitmap
, bmpDisabled
, kind
,
191 clientData
, shortHelp
, longHelp
));
194 wxToolBarToolBase
*wxToolBarBase::AddTool(wxToolBarToolBase
*tool
)
196 return InsertTool(GetToolsCount(), tool
);
200 wxToolBarBase::InsertTool(size_t pos
, wxToolBarToolBase
*tool
)
202 wxCHECK_MSG( pos
<= GetToolsCount(), NULL
,
203 wxT("invalid position in wxToolBar::InsertTool()") );
205 if ( !tool
|| !DoInsertTool(pos
, tool
) )
210 m_tools
.Insert(pos
, tool
);
217 wxToolBarBase::AddControl(wxControl
*control
, const wxString
& label
)
219 return InsertControl(GetToolsCount(), control
, label
);
223 wxToolBarBase::InsertControl(size_t pos
,
225 const wxString
& label
)
227 wxCHECK_MSG( control
, NULL
,
228 wxT("toolbar: can't insert NULL control") );
230 wxCHECK_MSG( control
->GetParent() == this, NULL
,
231 wxT("control must have toolbar as parent") );
233 return DoInsertNewTool(pos
, CreateTool(control
, label
));
236 wxControl
*wxToolBarBase::FindControl( int id
)
238 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
240 node
= node
->GetNext() )
242 const wxToolBarToolBase
* const tool
= node
->GetData();
243 if ( tool
->IsControl() )
245 wxControl
* const control
= tool
->GetControl();
249 wxFAIL_MSG( wxT("NULL control in toolbar?") );
251 else if ( control
->GetId() == id
)
262 wxToolBarToolBase
*wxToolBarBase::AddSeparator()
264 return InsertSeparator(GetToolsCount());
267 wxToolBarToolBase
*wxToolBarBase::InsertSeparator(size_t pos
)
269 return DoInsertNewTool(pos
, CreateSeparator());
272 wxToolBarToolBase
*wxToolBarBase::AddStretchableSpace()
274 return InsertStretchableSpace(GetToolsCount());
277 wxToolBarToolBase
*wxToolBarBase::InsertStretchableSpace(size_t pos
)
279 wxToolBarToolBase
* const tool
= CreateSeparator();
282 // this is a hack but we know that all the current implementations
283 // don't really use the tool when it's created, they will do it
284 // InsertTool() at earliest and maybe even in Realize() much later
286 // so we can create the tool as a plain separator and mark it as being
287 // a stretchable space later
288 tool
->MakeStretchable();
291 return DoInsertNewTool(pos
, tool
);
294 wxToolBarToolBase
*wxToolBarBase::RemoveTool(int id
)
297 wxToolBarToolsList::compatibility_iterator node
;
298 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
300 if ( node
->GetData()->GetId() == id
)
308 // don't give any error messages - sometimes we might call RemoveTool()
309 // without knowing whether the tool is or not in the toolbar
313 wxToolBarToolBase
*tool
= node
->GetData();
314 wxCHECK_MSG( tool
, NULL
, "NULL tool in the tools list?" );
316 if ( !DoDeleteTool(pos
, tool
) )
326 bool wxToolBarBase::DeleteToolByPos(size_t pos
)
328 wxCHECK_MSG( pos
< GetToolsCount(), false,
329 wxT("invalid position in wxToolBar::DeleteToolByPos()") );
331 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Item(pos
);
333 if ( !DoDeleteTool(pos
, node
->GetData()) )
338 delete node
->GetData();
344 bool wxToolBarBase::DeleteTool(int id
)
347 wxToolBarToolsList::compatibility_iterator node
;
348 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
350 if ( node
->GetData()->GetId() == id
)
356 if ( !node
|| !DoDeleteTool(pos
, node
->GetData()) )
361 delete node
->GetData();
367 wxToolBarToolBase
*wxToolBarBase::FindById(int id
) const
369 wxToolBarToolBase
*tool
= NULL
;
371 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
373 node
= node
->GetNext() )
375 tool
= node
->GetData();
376 if ( tool
->GetId() == id
)
388 void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase
*tool
)
390 wxCHECK_RET( tool
, wxT("NULL tool in wxToolBarTool::UnToggleRadioGroup") );
392 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO
)
395 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Find(tool
);
396 wxCHECK_RET( node
, wxT("invalid tool in wxToolBarTool::UnToggleRadioGroup") );
398 wxToolBarToolsList::compatibility_iterator nodeNext
= node
->GetNext();
401 wxToolBarToolBase
*toolNext
= nodeNext
->GetData();
403 if ( !toolNext
->IsButton() || toolNext
->GetKind() != wxITEM_RADIO
)
406 if ( toolNext
->Toggle(false) )
408 DoToggleTool(toolNext
, false);
411 nodeNext
= nodeNext
->GetNext();
414 wxToolBarToolsList::compatibility_iterator nodePrev
= node
->GetPrevious();
417 wxToolBarToolBase
*toolNext
= nodePrev
->GetData();
419 if ( !toolNext
->IsButton() || toolNext
->GetKind() != wxITEM_RADIO
)
422 if ( toolNext
->Toggle(false) )
424 DoToggleTool(toolNext
, false);
427 nodePrev
= nodePrev
->GetPrevious();
431 void wxToolBarBase::ClearTools()
433 while ( GetToolsCount() )
439 void wxToolBarBase::AdjustToolBitmapSize()
441 const wxSize
sizeOrig(m_defaultWidth
, m_defaultHeight
);
443 wxSize
sizeActual(sizeOrig
);
445 for ( wxToolBarToolsList::const_iterator i
= m_tools
.begin();
449 const wxBitmap
& bmp
= (*i
)->GetNormalBitmap();
451 sizeActual
.IncTo(bmp
.GetSize());
454 if ( sizeActual
!= sizeOrig
)
455 SetToolBitmapSize(sizeActual
);
458 bool wxToolBarBase::Realize()
460 // check if we have anything to do
461 if ( m_tools
.empty() )
464 // make sure tool size is large enough for all bitmaps to fit in
465 AdjustToolBitmapSize();
470 wxToolBarBase::~wxToolBarBase()
472 WX_CLEAR_LIST(wxToolBarToolsList
, m_tools
);
474 // notify the frame that it doesn't have a tool bar any longer to avoid
476 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
477 if ( frame
&& frame
->GetToolBar() == this )
479 frame
->SetToolBar(NULL
);
483 // ----------------------------------------------------------------------------
484 // wxToolBarBase tools state
485 // ----------------------------------------------------------------------------
487 void wxToolBarBase::EnableTool(int id
, bool enable
)
489 wxToolBarToolBase
*tool
= FindById(id
);
492 if ( tool
->Enable(enable
) )
494 DoEnableTool(tool
, enable
);
499 void wxToolBarBase::ToggleTool(int id
, bool toggle
)
501 wxToolBarToolBase
*tool
= FindById(id
);
502 if ( tool
&& tool
->CanBeToggled() )
504 if ( tool
->Toggle(toggle
) )
506 UnToggleRadioGroup(tool
);
507 DoToggleTool(tool
, toggle
);
512 void wxToolBarBase::SetToggle(int id
, bool toggle
)
514 wxToolBarToolBase
*tool
= FindById(id
);
517 if ( tool
->SetToggle(toggle
) )
519 DoSetToggle(tool
, toggle
);
524 void wxToolBarBase::SetToolShortHelp(int id
, const wxString
& help
)
526 wxToolBarToolBase
*tool
= FindById(id
);
529 (void)tool
->SetShortHelp(help
);
533 void wxToolBarBase::SetToolLongHelp(int id
, const wxString
& help
)
535 wxToolBarToolBase
*tool
= FindById(id
);
538 (void)tool
->SetLongHelp(help
);
542 wxObject
*wxToolBarBase::GetToolClientData(int id
) const
544 wxToolBarToolBase
*tool
= FindById(id
);
546 return tool
? tool
->GetClientData() : NULL
;
549 void wxToolBarBase::SetToolClientData(int id
, wxObject
*clientData
)
551 wxToolBarToolBase
*tool
= FindById(id
);
553 wxCHECK_RET( tool
, wxT("no such tool in wxToolBar::SetToolClientData") );
555 tool
->SetClientData(clientData
);
558 int wxToolBarBase::GetToolPos(int id
) const
561 wxToolBarToolsList::compatibility_iterator node
;
563 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
565 if ( node
->GetData()->GetId() == id
)
574 bool wxToolBarBase::GetToolState(int id
) const
576 wxToolBarToolBase
*tool
= FindById(id
);
577 wxCHECK_MSG( tool
, false, wxT("no such tool") );
579 return tool
->IsToggled();
582 bool wxToolBarBase::GetToolEnabled(int id
) const
584 wxToolBarToolBase
*tool
= FindById(id
);
585 wxCHECK_MSG( tool
, false, wxT("no such tool") );
587 return tool
->IsEnabled();
590 wxString
wxToolBarBase::GetToolShortHelp(int id
) const
592 wxToolBarToolBase
*tool
= FindById(id
);
593 wxCHECK_MSG( tool
, wxEmptyString
, wxT("no such tool") );
595 return tool
->GetShortHelp();
598 wxString
wxToolBarBase::GetToolLongHelp(int id
) const
600 wxToolBarToolBase
*tool
= FindById(id
);
601 wxCHECK_MSG( tool
, wxEmptyString
, wxT("no such tool") );
603 return tool
->GetLongHelp();
606 // ----------------------------------------------------------------------------
607 // wxToolBarBase geometry
608 // ----------------------------------------------------------------------------
610 void wxToolBarBase::SetMargins(int x
, int y
)
616 void wxToolBarBase::SetRows(int WXUNUSED(nRows
))
621 bool wxToolBarBase::IsVertical() const
623 return HasFlag(wxTB_LEFT
| wxTB_RIGHT
);
627 // ----------------------------------------------------------------------------
629 // ----------------------------------------------------------------------------
631 // Only allow toggle if returns true
632 bool wxToolBarBase::OnLeftClick(int id
, bool toggleDown
)
634 wxCommandEvent
event(wxEVT_COMMAND_TOOL_CLICKED
, id
);
635 event
.SetEventObject(this);
637 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
638 event
.SetInt((int)toggleDown
);
640 // and SetExtraLong() for backwards compatibility
641 event
.SetExtraLong((long)toggleDown
);
643 // Send events to this toolbar instead (and thence up the window hierarchy)
644 HandleWindowEvent(event
);
649 // Call when right button down.
650 void wxToolBarBase::OnRightClick(int id
,
654 wxCommandEvent
event(wxEVT_COMMAND_TOOL_RCLICKED
, id
);
655 event
.SetEventObject(this);
658 GetEventHandler()->ProcessEvent(event
);
661 // Called when the mouse cursor enters a tool bitmap (no button pressed).
662 // Argument is wxID_ANY if mouse is exiting the toolbar.
663 // Note that for this event, the id of the window is used,
664 // and the integer parameter of wxCommandEvent is used to retrieve
666 void wxToolBarBase::OnMouseEnter(int id
)
668 wxCommandEvent
event(wxEVT_COMMAND_TOOL_ENTER
, GetId());
669 event
.SetEventObject(this);
672 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
676 if ( id
!= wxID_ANY
)
678 const wxToolBarToolBase
* const tool
= FindById(id
);
680 help
= tool
->GetLongHelp();
683 // call DoGiveHelp() even if help string is empty to avoid showing the
684 // help for the previously selected tool when another one is selected
685 frame
->DoGiveHelp(help
, id
!= wxID_ANY
);
688 (void)GetEventHandler()->ProcessEvent(event
);
691 // ----------------------------------------------------------------------------
693 // ----------------------------------------------------------------------------
695 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
696 void wxToolBarBase::UpdateWindowUI(long flags
)
698 wxWindowBase::UpdateWindowUI(flags
);
700 // don't waste time updating state of tools in a hidden toolbar
704 // There is no sense in updating the toolbar UI
705 // if the parent window is about to get destroyed
706 wxWindow
*tlw
= wxGetTopLevelParent( this );
707 if (tlw
&& wxPendingDelete
.Member( tlw
))
710 wxEvtHandler
* evtHandler
= GetEventHandler() ;
712 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
714 node
= node
->GetNext() )
716 wxToolBarToolBase
* const tool
= node
->GetData();
717 if ( tool
->IsSeparator() )
720 int id
= tool
->GetId();
722 wxUpdateUIEvent
event(id
);
723 event
.SetEventObject(this);
725 if ( evtHandler
->ProcessEvent(event
) )
727 if ( event
.GetSetEnabled() )
728 EnableTool(id
, event
.GetEnabled());
729 if ( event
.GetSetChecked() )
730 ToggleTool(id
, event
.GetChecked());
732 if ( event
.GetSetText() )
740 bool wxToolBarBase::SetDropdownMenu(int toolid
, wxMenu
* menu
)
742 wxToolBarToolBase
* const tool
= FindById(toolid
);
743 wxCHECK_MSG( tool
, false, wxT("invalid tool id") );
745 wxCHECK_MSG( tool
->GetKind() == wxITEM_DROPDOWN
, false,
746 wxT("menu can be only associated with drop down tools") );
748 tool
->SetDropdownMenu(menu
);
754 #if WXWIN_COMPATIBILITY_2_8
756 bool wxCreateGreyedImage(const wxImage
& in
, wxImage
& out
)
759 out
= in
.ConvertToGreyscale();
762 #endif // wxUSE_IMAGE
766 #endif // WXWIN_COMPATIBILITY_2_8
768 #endif // wxUSE_TOOLBAR