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 // ----------------------------------------------------------------------------
43 // ----------------------------------------------------------------------------
45 BEGIN_EVENT_TABLE(wxToolBarBase
, wxControl
)
48 #include "wx/listimpl.cpp"
50 WX_DEFINE_LIST(wxToolBarToolsList
)
52 // ============================================================================
54 // ============================================================================
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase
, wxObject
)
62 wxToolBarToolBase::~wxToolBarToolBase()
65 delete m_dropdownMenu
;
69 GetControl()->Destroy();
73 bool wxToolBarToolBase::Enable(bool enable
)
75 if ( m_enabled
== enable
)
83 bool wxToolBarToolBase::Toggle(bool toggle
)
85 wxASSERT_MSG( CanBeToggled(), wxT("can't toggle this tool") );
87 if ( m_toggled
== toggle
)
95 bool wxToolBarToolBase::SetToggle(bool toggle
)
97 wxItemKind kind
= toggle
? wxITEM_CHECK
: wxITEM_NORMAL
;
106 bool wxToolBarToolBase::SetShortHelp(const wxString
& help
)
108 if ( m_shortHelpString
== help
)
111 m_shortHelpString
= help
;
116 bool wxToolBarToolBase::SetLongHelp(const wxString
& help
)
118 if ( m_longHelpString
== help
)
121 m_longHelpString
= help
;
128 void wxToolBarToolBase::SetDropdownMenu(wxMenu
* menu
)
130 delete m_dropdownMenu
;
131 m_dropdownMenu
= menu
;
136 // ----------------------------------------------------------------------------
137 // wxToolBarBase adding/deleting items
138 // ----------------------------------------------------------------------------
140 wxToolBarBase::wxToolBarBase()
142 // the list owns the pointers
143 m_xMargin
= m_yMargin
= 0;
144 m_maxRows
= m_maxCols
= 0;
145 m_toolPacking
= m_toolSeparation
= 0;
147 m_defaultHeight
= 15;
150 void wxToolBarBase::FixupStyle()
152 if ( !HasFlag(wxTB_TOP
| wxTB_LEFT
| wxTB_RIGHT
| wxTB_BOTTOM
) )
154 // this is the default
155 m_windowStyle
|= wxTB_TOP
;
159 wxToolBarToolBase
*wxToolBarBase::DoAddTool(int id
,
160 const wxString
& label
,
161 const wxBitmap
& bitmap
,
162 const wxBitmap
& bmpDisabled
,
164 const wxString
& shortHelp
,
165 const wxString
& longHelp
,
166 wxObject
*clientData
,
167 wxCoord
WXUNUSED(xPos
),
168 wxCoord
WXUNUSED(yPos
))
170 InvalidateBestSize();
171 return InsertTool(GetToolsCount(), id
, label
, bitmap
, bmpDisabled
,
172 kind
, shortHelp
, longHelp
, clientData
);
175 wxToolBarToolBase
*wxToolBarBase::InsertTool(size_t pos
,
177 const wxString
& label
,
178 const wxBitmap
& bitmap
,
179 const wxBitmap
& bmpDisabled
,
181 const wxString
& shortHelp
,
182 const wxString
& longHelp
,
183 wxObject
*clientData
)
185 wxCHECK_MSG( pos
<= GetToolsCount(), NULL
,
186 wxT("invalid position in wxToolBar::InsertTool()") );
188 return DoInsertNewTool(pos
, CreateTool(id
, label
, bitmap
, bmpDisabled
, kind
,
189 clientData
, shortHelp
, longHelp
));
192 wxToolBarToolBase
*wxToolBarBase::AddTool(wxToolBarToolBase
*tool
)
194 return InsertTool(GetToolsCount(), tool
);
198 wxToolBarBase::InsertTool(size_t pos
, wxToolBarToolBase
*tool
)
200 wxCHECK_MSG( pos
<= GetToolsCount(), NULL
,
201 wxT("invalid position in wxToolBar::InsertTool()") );
203 if ( !tool
|| !DoInsertTool(pos
, tool
) )
208 m_tools
.Insert(pos
, tool
);
215 wxToolBarBase::AddControl(wxControl
*control
, const wxString
& label
)
217 return InsertControl(GetToolsCount(), control
, label
);
221 wxToolBarBase::InsertControl(size_t pos
,
223 const wxString
& label
)
225 wxCHECK_MSG( control
, NULL
,
226 wxT("toolbar: can't insert NULL control") );
228 wxCHECK_MSG( control
->GetParent() == this, NULL
,
229 wxT("control must have toolbar as parent") );
231 return DoInsertNewTool(pos
, CreateTool(control
, label
));
234 wxControl
*wxToolBarBase::FindControl( int id
)
236 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
238 node
= node
->GetNext() )
240 const wxToolBarToolBase
* const tool
= node
->GetData();
241 if ( tool
->IsControl() )
243 wxControl
* const control
= tool
->GetControl();
247 wxFAIL_MSG( wxT("NULL control in toolbar?") );
249 else if ( control
->GetId() == id
)
260 wxToolBarToolBase
*wxToolBarBase::AddSeparator()
262 return InsertSeparator(GetToolsCount());
265 wxToolBarToolBase
*wxToolBarBase::InsertSeparator(size_t pos
)
267 return DoInsertNewTool(pos
, CreateSeparator());
270 wxToolBarToolBase
*wxToolBarBase::AddStretchableSpace()
272 return InsertStretchableSpace(GetToolsCount());
275 wxToolBarToolBase
*wxToolBarBase::InsertStretchableSpace(size_t pos
)
277 wxToolBarToolBase
* const tool
= CreateSeparator();
280 // this is a hack but we know that all the current implementations
281 // don't really use the tool when it's created, they will do it
282 // InsertTool() at earliest and maybe even in Realize() much later
284 // so we can create the tool as a plain separator and mark it as being
285 // a stretchable space later
286 tool
->MakeStretchable();
289 return DoInsertNewTool(pos
, tool
);
292 wxToolBarToolBase
*wxToolBarBase::RemoveTool(int id
)
295 wxToolBarToolsList::compatibility_iterator node
;
296 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
298 if ( node
->GetData()->GetId() == id
)
306 // don't give any error messages - sometimes we might call RemoveTool()
307 // without knowing whether the tool is or not in the toolbar
311 wxToolBarToolBase
*tool
= node
->GetData();
312 wxCHECK_MSG( tool
, NULL
, "NULL tool in the tools list?" );
314 if ( !DoDeleteTool(pos
, tool
) )
324 bool wxToolBarBase::DeleteToolByPos(size_t pos
)
326 wxCHECK_MSG( pos
< GetToolsCount(), false,
327 wxT("invalid position in wxToolBar::DeleteToolByPos()") );
329 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Item(pos
);
331 if ( !DoDeleteTool(pos
, node
->GetData()) )
336 delete node
->GetData();
342 bool wxToolBarBase::DeleteTool(int id
)
345 wxToolBarToolsList::compatibility_iterator node
;
346 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
348 if ( node
->GetData()->GetId() == id
)
354 if ( !node
|| !DoDeleteTool(pos
, node
->GetData()) )
359 delete node
->GetData();
365 wxToolBarToolBase
*wxToolBarBase::FindById(int id
) const
367 wxToolBarToolBase
*tool
= NULL
;
369 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
371 node
= node
->GetNext() )
373 tool
= node
->GetData();
374 if ( tool
->GetId() == id
)
386 void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase
*tool
)
388 wxCHECK_RET( tool
, wxT("NULL tool in wxToolBarTool::UnToggleRadioGroup") );
390 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO
)
393 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Find(tool
);
394 wxCHECK_RET( node
, wxT("invalid tool in wxToolBarTool::UnToggleRadioGroup") );
396 wxToolBarToolsList::compatibility_iterator nodeNext
= node
->GetNext();
399 wxToolBarToolBase
*toolNext
= nodeNext
->GetData();
401 if ( !toolNext
->IsButton() || toolNext
->GetKind() != wxITEM_RADIO
)
404 if ( toolNext
->Toggle(false) )
406 DoToggleTool(toolNext
, false);
409 nodeNext
= nodeNext
->GetNext();
412 wxToolBarToolsList::compatibility_iterator nodePrev
= node
->GetPrevious();
415 wxToolBarToolBase
*toolNext
= nodePrev
->GetData();
417 if ( !toolNext
->IsButton() || toolNext
->GetKind() != wxITEM_RADIO
)
420 if ( toolNext
->Toggle(false) )
422 DoToggleTool(toolNext
, false);
425 nodePrev
= nodePrev
->GetPrevious();
429 void wxToolBarBase::ClearTools()
431 while ( GetToolsCount() )
437 void wxToolBarBase::AdjustToolBitmapSize()
439 const wxSize
sizeOrig(m_defaultWidth
, m_defaultHeight
);
441 wxSize
sizeActual(sizeOrig
);
443 for ( wxToolBarToolsList::const_iterator i
= m_tools
.begin();
447 const wxBitmap
& bmp
= (*i
)->GetNormalBitmap();
449 sizeActual
.IncTo(bmp
.GetSize());
452 if ( sizeActual
!= sizeOrig
)
453 SetToolBitmapSize(sizeActual
);
456 bool wxToolBarBase::Realize()
458 // check if we have anything to do
459 if ( m_tools
.empty() )
462 // make sure tool size is large enough for all bitmaps to fit in
463 AdjustToolBitmapSize();
468 wxToolBarBase::~wxToolBarBase()
470 WX_CLEAR_LIST(wxToolBarToolsList
, m_tools
);
472 // notify the frame that it doesn't have a tool bar any longer to avoid
474 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
475 if ( frame
&& frame
->GetToolBar() == this )
477 frame
->SetToolBar(NULL
);
481 // ----------------------------------------------------------------------------
482 // wxToolBarBase tools state
483 // ----------------------------------------------------------------------------
485 void wxToolBarBase::EnableTool(int id
, bool enable
)
487 wxToolBarToolBase
*tool
= FindById(id
);
490 if ( tool
->Enable(enable
) )
492 DoEnableTool(tool
, enable
);
497 void wxToolBarBase::ToggleTool(int id
, bool toggle
)
499 wxToolBarToolBase
*tool
= FindById(id
);
500 if ( tool
&& tool
->CanBeToggled() )
502 if ( tool
->Toggle(toggle
) )
504 UnToggleRadioGroup(tool
);
505 DoToggleTool(tool
, toggle
);
510 void wxToolBarBase::SetToggle(int id
, bool toggle
)
512 wxToolBarToolBase
*tool
= FindById(id
);
515 if ( tool
->SetToggle(toggle
) )
517 DoSetToggle(tool
, toggle
);
522 void wxToolBarBase::SetToolShortHelp(int id
, const wxString
& help
)
524 wxToolBarToolBase
*tool
= FindById(id
);
527 (void)tool
->SetShortHelp(help
);
531 void wxToolBarBase::SetToolLongHelp(int id
, const wxString
& help
)
533 wxToolBarToolBase
*tool
= FindById(id
);
536 (void)tool
->SetLongHelp(help
);
540 wxObject
*wxToolBarBase::GetToolClientData(int id
) const
542 wxToolBarToolBase
*tool
= FindById(id
);
544 return tool
? tool
->GetClientData() : NULL
;
547 void wxToolBarBase::SetToolClientData(int id
, wxObject
*clientData
)
549 wxToolBarToolBase
*tool
= FindById(id
);
551 wxCHECK_RET( tool
, wxT("no such tool in wxToolBar::SetToolClientData") );
553 tool
->SetClientData(clientData
);
556 int wxToolBarBase::GetToolPos(int id
) const
559 wxToolBarToolsList::compatibility_iterator node
;
561 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
563 if ( node
->GetData()->GetId() == id
)
572 bool wxToolBarBase::GetToolState(int id
) const
574 wxToolBarToolBase
*tool
= FindById(id
);
575 wxCHECK_MSG( tool
, false, wxT("no such tool") );
577 return tool
->IsToggled();
580 bool wxToolBarBase::GetToolEnabled(int id
) const
582 wxToolBarToolBase
*tool
= FindById(id
);
583 wxCHECK_MSG( tool
, false, wxT("no such tool") );
585 return tool
->IsEnabled();
588 wxString
wxToolBarBase::GetToolShortHelp(int id
) const
590 wxToolBarToolBase
*tool
= FindById(id
);
591 wxCHECK_MSG( tool
, wxEmptyString
, wxT("no such tool") );
593 return tool
->GetShortHelp();
596 wxString
wxToolBarBase::GetToolLongHelp(int id
) const
598 wxToolBarToolBase
*tool
= FindById(id
);
599 wxCHECK_MSG( tool
, wxEmptyString
, wxT("no such tool") );
601 return tool
->GetLongHelp();
604 // ----------------------------------------------------------------------------
605 // wxToolBarBase geometry
606 // ----------------------------------------------------------------------------
608 void wxToolBarBase::SetMargins(int x
, int y
)
614 void wxToolBarBase::SetRows(int WXUNUSED(nRows
))
619 bool wxToolBarBase::IsVertical() const
621 return HasFlag(wxTB_LEFT
| wxTB_RIGHT
);
625 // ----------------------------------------------------------------------------
627 // ----------------------------------------------------------------------------
629 // Only allow toggle if returns true
630 bool wxToolBarBase::OnLeftClick(int id
, bool toggleDown
)
632 wxCommandEvent
event(wxEVT_COMMAND_TOOL_CLICKED
, id
);
633 event
.SetEventObject(this);
635 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
636 event
.SetInt((int)toggleDown
);
638 // and SetExtraLong() for backwards compatibility
639 event
.SetExtraLong((long)toggleDown
);
641 // Send events to this toolbar instead (and thence up the window hierarchy)
642 HandleWindowEvent(event
);
647 // Call when right button down.
648 void wxToolBarBase::OnRightClick(int id
,
652 wxCommandEvent
event(wxEVT_COMMAND_TOOL_RCLICKED
, id
);
653 event
.SetEventObject(this);
656 GetEventHandler()->ProcessEvent(event
);
659 // Called when the mouse cursor enters a tool bitmap (no button pressed).
660 // Argument is wxID_ANY if mouse is exiting the toolbar.
661 // Note that for this event, the id of the window is used,
662 // and the integer parameter of wxCommandEvent is used to retrieve
664 void wxToolBarBase::OnMouseEnter(int id
)
666 wxCommandEvent
event(wxEVT_COMMAND_TOOL_ENTER
, GetId());
667 event
.SetEventObject(this);
670 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
674 if ( id
!= wxID_ANY
)
676 const wxToolBarToolBase
* const tool
= FindById(id
);
678 help
= tool
->GetLongHelp();
681 // call DoGiveHelp() even if help string is empty to avoid showing the
682 // help for the previously selected tool when another one is selected
683 frame
->DoGiveHelp(help
, id
!= wxID_ANY
);
686 (void)GetEventHandler()->ProcessEvent(event
);
689 // ----------------------------------------------------------------------------
691 // ----------------------------------------------------------------------------
693 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
694 void wxToolBarBase::UpdateWindowUI(long flags
)
696 wxWindowBase::UpdateWindowUI(flags
);
698 // don't waste time updating state of tools in a hidden toolbar
702 // There is no sense in updating the toolbar UI
703 // if the parent window is about to get destroyed
704 wxWindow
*tlw
= wxGetTopLevelParent( this );
705 if (tlw
&& wxPendingDelete
.Member( tlw
))
708 wxEvtHandler
* evtHandler
= GetEventHandler() ;
710 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
712 node
= node
->GetNext() )
714 wxToolBarToolBase
* const tool
= node
->GetData();
715 if ( tool
->IsSeparator() )
718 int id
= tool
->GetId();
720 wxUpdateUIEvent
event(id
);
721 event
.SetEventObject(this);
723 if ( evtHandler
->ProcessEvent(event
) )
725 if ( event
.GetSetEnabled() )
726 EnableTool(id
, event
.GetEnabled());
727 if ( event
.GetSetChecked() )
728 ToggleTool(id
, event
.GetChecked());
730 if ( event
.GetSetText() )
738 bool wxToolBarBase::SetDropdownMenu(int toolid
, wxMenu
* menu
)
740 wxToolBarToolBase
* const tool
= FindById(toolid
);
741 wxCHECK_MSG( tool
, false, wxT("invalid tool id") );
743 wxCHECK_MSG( tool
->GetKind() == wxITEM_DROPDOWN
, false,
744 wxT("menu can be only associated with drop down tools") );
746 tool
->SetDropdownMenu(menu
);
752 #if WXWIN_COMPATIBILITY_2_8
754 bool wxCreateGreyedImage(const wxImage
& in
, wxImage
& out
)
757 out
= in
.ConvertToGreyscale();
760 #endif // wxUSE_IMAGE
764 #endif // WXWIN_COMPATIBILITY_2_8
766 #endif // wxUSE_TOOLBAR