1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/tbarbase.cpp
3 // Purpose: wxToolBarBase implementation
4 // Author: Julian Smart
5 // Modified by: VZ at 11.12.99 (wxScrollableToolBar splitted off)
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21 #pragma implementation "tbarbase.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
34 #include "wx/control.h"
39 #include "wx/settings.h"
41 #include "wx/toolbar.h"
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 bool wxToolBarToolBase::Enable(bool enable
)
66 if ( m_enabled
== enable
)
74 bool wxToolBarToolBase::Toggle(bool toggle
)
76 wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") );
78 if ( m_toggled
== toggle
)
86 bool wxToolBarToolBase::SetToggle(bool toggle
)
88 wxItemKind kind
= toggle
? wxITEM_CHECK
: wxITEM_NORMAL
;
97 bool wxToolBarToolBase::SetShortHelp(const wxString
& help
)
99 if ( m_shortHelpString
== help
)
102 m_shortHelpString
= help
;
107 bool wxToolBarToolBase::SetLongHelp(const wxString
& help
)
109 if ( m_longHelpString
== help
)
112 m_longHelpString
= help
;
117 #if WXWIN_COMPATIBILITY_2_2
119 const wxBitmap
& wxToolBarToolBase::GetBitmap1() const
121 return GetNormalBitmap();
124 const wxBitmap
& wxToolBarToolBase::GetBitmap2() const
126 return GetDisabledBitmap();
129 void wxToolBarToolBase::SetBitmap1(const wxBitmap
& bmp
)
131 SetNormalBitmap(bmp
);
134 void wxToolBarToolBase::SetBitmap2(const wxBitmap
& bmp
)
136 SetDisabledBitmap(bmp
);
139 #endif // WXWIN_COMPATIBILITY_2_2
141 // ----------------------------------------------------------------------------
142 // wxToolBarBase adding/deleting items
143 // ----------------------------------------------------------------------------
145 wxToolBarBase::wxToolBarBase()
147 // the list owns the pointers
148 m_xMargin
= m_yMargin
= 0;
149 m_maxRows
= m_maxCols
= 0;
150 m_toolPacking
= m_toolSeparation
= 0;
152 m_defaultHeight
= 15;
155 wxToolBarToolBase
*wxToolBarBase::DoAddTool(int id
,
156 const wxString
& label
,
157 const wxBitmap
& bitmap
,
158 const wxBitmap
& bmpDisabled
,
160 const wxString
& shortHelp
,
161 const wxString
& longHelp
,
162 wxObject
*clientData
,
163 wxCoord
WXUNUSED(xPos
),
164 wxCoord
WXUNUSED(yPos
))
166 InvalidateBestSize();
167 return InsertTool(GetToolsCount(), id
, label
, bitmap
, bmpDisabled
,
168 kind
, shortHelp
, longHelp
, clientData
);
171 wxToolBarToolBase
*wxToolBarBase::InsertTool(size_t pos
,
173 const wxString
& label
,
174 const wxBitmap
& bitmap
,
175 const wxBitmap
& bmpDisabled
,
177 const wxString
& shortHelp
,
178 const wxString
& longHelp
,
179 wxObject
*clientData
)
181 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
182 _T("invalid position in wxToolBar::InsertTool()") );
184 wxToolBarToolBase
*tool
= CreateTool(id
, label
, bitmap
, bmpDisabled
, kind
,
185 clientData
, shortHelp
, longHelp
);
187 if ( !InsertTool(pos
, tool
) )
197 wxToolBarToolBase
*wxToolBarBase::AddTool(wxToolBarToolBase
*tool
)
199 return InsertTool(GetToolsCount(), tool
);
203 wxToolBarBase::InsertTool(size_t pos
, wxToolBarToolBase
*tool
)
205 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
206 _T("invalid position in wxToolBar::InsertTool()") );
208 if ( !tool
|| !DoInsertTool(pos
, tool
) )
213 m_tools
.Insert(pos
, tool
);
218 wxToolBarToolBase
*wxToolBarBase::AddControl(wxControl
*control
)
220 return InsertControl(GetToolsCount(), control
);
223 wxToolBarToolBase
*wxToolBarBase::InsertControl(size_t pos
, wxControl
*control
)
225 wxCHECK_MSG( control
, (wxToolBarToolBase
*)NULL
,
226 _T("toolbar: can't insert NULL control") );
228 wxCHECK_MSG( control
->GetParent() == this, (wxToolBarToolBase
*)NULL
,
229 _T("control must have toolbar as parent") );
231 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
232 _T("invalid position in wxToolBar::InsertControl()") );
234 wxToolBarToolBase
*tool
= CreateTool(control
);
236 if ( !InsertTool(pos
, tool
) )
246 wxControl
*wxToolBarBase::FindControl( int id
)
248 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
250 node
= node
->GetNext() )
252 const wxToolBarToolBase
* const tool
= node
->GetData();
253 if ( tool
->IsControl() )
255 wxControl
* const control
= tool
->GetControl();
259 wxFAIL_MSG( _T("NULL control in toolbar?") );
261 else if ( control
->GetId() == id
)
272 wxToolBarToolBase
*wxToolBarBase::AddSeparator()
274 return InsertSeparator(GetToolsCount());
277 wxToolBarToolBase
*wxToolBarBase::InsertSeparator(size_t pos
)
279 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
280 _T("invalid position in wxToolBar::InsertSeparator()") );
282 wxToolBarToolBase
*tool
= CreateTool(wxID_SEPARATOR
,
284 wxNullBitmap
, wxNullBitmap
,
285 wxITEM_SEPARATOR
, (wxObject
*)NULL
,
286 wxEmptyString
, wxEmptyString
);
288 if ( !tool
|| !DoInsertTool(pos
, tool
) )
295 m_tools
.Insert(pos
, tool
);
300 wxToolBarToolBase
*wxToolBarBase::RemoveTool(int id
)
303 wxToolBarToolsList::compatibility_iterator node
;
304 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
306 if ( node
->GetData()->GetId() == id
)
314 // don't give any error messages - sometimes we might call RemoveTool()
315 // without knowing whether the tool is or not in the toolbar
316 return (wxToolBarToolBase
*)NULL
;
319 wxToolBarToolBase
*tool
= node
->GetData();
320 if ( !DoDeleteTool(pos
, tool
) )
322 return (wxToolBarToolBase
*)NULL
;
330 bool wxToolBarBase::DeleteToolByPos(size_t pos
)
332 wxCHECK_MSG( pos
< GetToolsCount(), false,
333 _T("invalid position in wxToolBar::DeleteToolByPos()") );
335 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Item(pos
);
337 if ( !DoDeleteTool(pos
, node
->GetData()) )
342 delete node
->GetData();
348 bool wxToolBarBase::DeleteTool(int id
)
351 wxToolBarToolsList::compatibility_iterator node
;
352 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
354 if ( node
->GetData()->GetId() == id
)
360 if ( !node
|| !DoDeleteTool(pos
, node
->GetData()) )
365 delete node
->GetData();
371 wxToolBarToolBase
*wxToolBarBase::FindById(int id
) const
373 wxToolBarToolBase
*tool
= (wxToolBarToolBase
*)NULL
;
375 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
377 node
= node
->GetNext() )
379 tool
= node
->GetData();
380 if ( tool
->GetId() == id
)
392 void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase
*tool
)
394 wxCHECK_RET( tool
, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") );
396 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO
)
399 wxToolBarToolsList::compatibility_iterator node
= m_tools
.Find(tool
);
400 wxCHECK_RET( node
, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") );
402 wxToolBarToolsList::compatibility_iterator nodeNext
= node
->GetNext();
405 wxToolBarToolBase
*tool
= nodeNext
->GetData();
407 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO
)
410 if ( tool
->Toggle(false) )
412 DoToggleTool(tool
, false);
415 nodeNext
= nodeNext
->GetNext();
418 wxToolBarToolsList::compatibility_iterator nodePrev
= node
->GetPrevious();
421 wxToolBarToolBase
*tool
= nodePrev
->GetData();
423 if ( !tool
->IsButton() || tool
->GetKind() != wxITEM_RADIO
)
426 if ( tool
->Toggle(false) )
428 DoToggleTool(tool
, false);
431 nodePrev
= nodePrev
->GetPrevious();
435 void wxToolBarBase::ClearTools()
437 WX_CLEAR_LIST(wxToolBarToolsList
, m_tools
);
440 bool wxToolBarBase::Realize()
445 wxToolBarBase::~wxToolBarBase()
447 WX_CLEAR_LIST(wxToolBarToolsList
, m_tools
);
449 // notify the frame that it doesn't have a tool bar any longer to avoid
451 wxFrameBase
*frame
= wxDynamicCast(GetParent(), wxFrameBase
);
452 if ( frame
&& frame
->GetToolBar() == this )
454 frame
->SetToolBar(NULL
);
458 // ----------------------------------------------------------------------------
459 // wxToolBarBase tools state
460 // ----------------------------------------------------------------------------
462 void wxToolBarBase::EnableTool(int id
, bool enable
)
464 wxToolBarToolBase
*tool
= FindById(id
);
467 if ( tool
->Enable(enable
) )
469 DoEnableTool(tool
, enable
);
474 void wxToolBarBase::ToggleTool(int id
, bool toggle
)
476 wxToolBarToolBase
*tool
= FindById(id
);
477 if ( tool
&& tool
->CanBeToggled() )
479 if ( tool
->Toggle(toggle
) )
481 UnToggleRadioGroup(tool
);
482 DoToggleTool(tool
, toggle
);
487 void wxToolBarBase::SetToggle(int id
, bool toggle
)
489 wxToolBarToolBase
*tool
= FindById(id
);
492 if ( tool
->SetToggle(toggle
) )
494 DoSetToggle(tool
, toggle
);
499 void wxToolBarBase::SetToolShortHelp(int id
, const wxString
& help
)
501 wxToolBarToolBase
*tool
= FindById(id
);
504 (void)tool
->SetShortHelp(help
);
508 void wxToolBarBase::SetToolLongHelp(int id
, const wxString
& help
)
510 wxToolBarToolBase
*tool
= FindById(id
);
513 (void)tool
->SetLongHelp(help
);
517 wxObject
*wxToolBarBase::GetToolClientData(int id
) const
519 wxToolBarToolBase
*tool
= FindById(id
);
521 return tool
? tool
->GetClientData() : (wxObject
*)NULL
;
524 void wxToolBarBase::SetToolClientData(int id
, wxObject
*clientData
)
526 wxToolBarToolBase
*tool
= FindById(id
);
528 wxCHECK_RET( tool
, _T("no such tool in wxToolBar::SetToolClientData") );
530 tool
->SetClientData(clientData
);
533 int wxToolBarBase::GetToolPos(int id
) const
536 wxToolBarToolsList::compatibility_iterator node
;
538 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
540 if ( node
->GetData()->GetId() == id
)
549 bool wxToolBarBase::GetToolState(int id
) const
551 wxToolBarToolBase
*tool
= FindById(id
);
552 wxCHECK_MSG( tool
, false, _T("no such tool") );
554 return tool
->IsToggled();
557 bool wxToolBarBase::GetToolEnabled(int id
) const
559 wxToolBarToolBase
*tool
= FindById(id
);
560 wxCHECK_MSG( tool
, false, _T("no such tool") );
562 return tool
->IsEnabled();
565 wxString
wxToolBarBase::GetToolShortHelp(int id
) const
567 wxToolBarToolBase
*tool
= FindById(id
);
568 wxCHECK_MSG( tool
, wxEmptyString
, _T("no such tool") );
570 return tool
->GetShortHelp();
573 wxString
wxToolBarBase::GetToolLongHelp(int id
) const
575 wxToolBarToolBase
*tool
= FindById(id
);
576 wxCHECK_MSG( tool
, wxEmptyString
, _T("no such tool") );
578 return tool
->GetLongHelp();
581 // ----------------------------------------------------------------------------
582 // wxToolBarBase geometry
583 // ----------------------------------------------------------------------------
585 void wxToolBarBase::SetMargins(int x
, int y
)
591 void wxToolBarBase::SetRows(int WXUNUSED(nRows
))
596 // ----------------------------------------------------------------------------
598 // ----------------------------------------------------------------------------
600 // Only allow toggle if returns true
601 bool wxToolBarBase::OnLeftClick(int id
, bool toggleDown
)
603 wxCommandEvent
event(wxEVT_COMMAND_TOOL_CLICKED
, id
);
604 event
.SetEventObject(this);
606 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
607 event
.SetInt((int)toggleDown
);
609 // and SetExtraLong() for backwards compatibility
610 event
.SetExtraLong((long)toggleDown
);
612 // Send events to this toolbar instead (and thence up the window hierarchy)
613 GetEventHandler()->ProcessEvent(event
);
618 // Call when right button down.
619 void wxToolBarBase::OnRightClick(int id
,
623 wxCommandEvent
event(wxEVT_COMMAND_TOOL_RCLICKED
, id
);
624 event
.SetEventObject(this);
627 GetEventHandler()->ProcessEvent(event
);
630 // Called when the mouse cursor enters a tool bitmap (no button pressed).
631 // Argument is wxID_ANY if mouse is exiting the toolbar.
632 // Note that for this event, the id of the window is used,
633 // and the integer parameter of wxCommandEvent is used to retrieve
635 void wxToolBarBase::OnMouseEnter(int id
)
637 wxCommandEvent
event(wxEVT_COMMAND_TOOL_ENTER
, GetId());
638 event
.SetEventObject(this);
641 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
645 wxToolBarToolBase
* tool
= id
== wxID_ANY
? (wxToolBarToolBase
*)NULL
: FindById(id
);
647 help
= tool
->GetLongHelp();
648 frame
->DoGiveHelp( help
, id
!= wxID_ANY
);
651 (void)GetEventHandler()->ProcessEvent(event
);
654 // ----------------------------------------------------------------------------
656 // ----------------------------------------------------------------------------
658 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
659 void wxToolBarBase::UpdateWindowUI(long flags
)
661 wxWindowBase::UpdateWindowUI(flags
);
663 // There is no sense in updating the toolbar UI
664 // if the parent window is about to get destroyed
665 wxWindow
*tlw
= wxGetTopLevelParent( this );
666 if (tlw
&& wxPendingDelete
.Member( tlw
))
669 wxEvtHandler
* evtHandler
= GetEventHandler() ;
671 for ( wxToolBarToolsList::compatibility_iterator node
= m_tools
.GetFirst();
673 node
= node
->GetNext() )
675 int id
= node
->GetData()->GetId();
677 wxUpdateUIEvent
event(id
);
678 event
.SetEventObject(this);
680 if ( evtHandler
->ProcessEvent(event
) )
682 if ( event
.GetSetEnabled() )
683 EnableTool(id
, event
.GetEnabled());
684 if ( event
.GetSetChecked() )
685 ToggleTool(id
, event
.GetChecked());
687 if ( event
.GetSetText() )
694 // Helper function, used by wxCreateGreyedImage
696 static void wxGreyOutImage( const wxImage
& src
,
698 const wxColour
& darkCol
,
699 const wxColour
& lightCol
,
700 const wxColour
& bgCol
)
702 // Second attempt, just making things monochrome
703 int width
= src
.GetWidth();
704 int height
= src
.GetHeight();
706 int redCur
, greenCur
, blueCur
;
707 for ( int x
= 0; x
< width
; x
++ )
709 for ( int y
= 1; y
< height
; y
++ )
711 redCur
= src
.GetRed(x
, y
);
712 greenCur
= src
.GetGreen(x
, y
);
713 blueCur
= src
.GetBlue(x
, y
);
715 // Change light things to the background colour
716 if ( redCur
>= (lightCol
.Red() - 50) && greenCur
>= (lightCol
.Green() - 50) && blueCur
>= (lightCol
.Blue() - 50) )
718 dest
.SetRGB(x
,y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue());
720 else if ( redCur
== bgCol
.Red() && greenCur
== bgCol
.Green() && blueCur
== bgCol
.Blue() )
722 // Leave the background colour as-is
723 // dest.SetRGB(x,y, bgCol.Red(), bgCol.Green(), bgCol.Blue());
725 else // if ( redCur <= darkCol.Red() && greenCur <= darkCol.Green() && blueCur <= darkCol.Blue() )
727 // Change dark things to really dark
728 dest
.SetRGB(x
,y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue());
735 * Make a greyed-out image suitable for disabled buttons.
736 * This code is adapted from wxNewBitmapButton in FL.
739 bool wxCreateGreyedImage(const wxImage
& in
, wxImage
& out
)
743 // assuming the pixels along the edges are of the background color
744 wxColour
bgCol(in
.GetRed(0, 0), in
.GetGreen(0, 0), in
.GetBlue(0, 0));
746 wxColour darkCol
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
) ;
747 wxColour lightCol
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
) ;
749 wxGreyOutImage(in
, out
, darkCol
, lightCol
, bgCol
);
754 #endif // wxUSE_TOOLBAR