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 and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
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"
46 #include "wx/tbarbase.h"
48 // ----------------------------------------------------------------------------
50 // ----------------------------------------------------------------------------
52 IMPLEMENT_CLASS(wxToolBarBase
, wxControl
)
54 BEGIN_EVENT_TABLE(wxToolBarBase
, wxControl
)
55 EVT_IDLE(wxToolBarBase::OnIdle
)
58 #include "wx/listimpl.cpp"
60 WX_DEFINE_LIST(wxToolBarToolsList
);
62 // ============================================================================
64 // ============================================================================
66 // ----------------------------------------------------------------------------
68 // ----------------------------------------------------------------------------
70 bool wxToolBarToolBase::Enable(bool enable
)
72 if ( m_enabled
== enable
)
80 bool wxToolBarToolBase::Toggle(bool toggle
)
82 wxASSERT_MSG( m_isToggle
, _T("can't toggle this tool") );
84 if ( m_toggled
== toggle
)
92 bool wxToolBarToolBase::SetToggle(bool toggle
)
94 if ( m_isToggle
== toggle
)
102 bool wxToolBarToolBase::SetShortHelp(const wxString
& help
)
104 if ( m_shortHelpString
== help
)
107 m_shortHelpString
= help
;
112 bool wxToolBarToolBase::SetLongHelp(const wxString
& help
)
114 if ( m_longHelpString
== help
)
117 m_longHelpString
= help
;
122 wxToolBarToolBase::~wxToolBarToolBase()
126 // ----------------------------------------------------------------------------
127 // wxToolBarBase adding/deleting items
128 // ----------------------------------------------------------------------------
130 wxToolBarBase::wxToolBarBase()
132 // the list owns the pointers
133 m_tools
.DeleteContents(TRUE
);
135 m_xMargin
= m_yMargin
= 0;
137 m_maxRows
= m_maxCols
= 0;
140 wxToolBarToolBase
*wxToolBarBase::AddTool(int id
,
141 const wxBitmap
& bitmap
,
142 const wxBitmap
& pushedBitmap
,
144 wxCoord
WXUNUSED(xPos
),
145 wxCoord
WXUNUSED(yPos
),
146 wxObject
*clientData
,
147 const wxString
& helpString1
,
148 const wxString
& helpString2
)
150 return InsertTool(GetToolsCount(), id
, bitmap
, pushedBitmap
,
151 toggle
, clientData
, helpString1
, helpString2
);
154 wxToolBarToolBase
*wxToolBarBase::InsertTool(size_t pos
,
156 const wxBitmap
& bitmap
,
157 const wxBitmap
& pushedBitmap
,
159 wxObject
*clientData
,
160 const wxString
& helpString1
,
161 const wxString
& helpString2
)
163 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
164 _T("invalid position in wxToolBar::InsertTool()") );
166 wxToolBarToolBase
*tool
= CreateTool(id
, bitmap
, pushedBitmap
, toggle
,
167 clientData
, helpString1
, helpString2
);
169 if ( !tool
|| !DoInsertTool(pos
, tool
) )
176 m_tools
.Insert(pos
, tool
);
181 wxToolBarToolBase
*wxToolBarBase::AddControl(wxControl
*control
)
183 return InsertControl(GetToolsCount(), control
);
186 wxToolBarToolBase
*wxToolBarBase::InsertControl(size_t pos
, wxControl
*control
)
188 wxCHECK_MSG( control
, (wxToolBarToolBase
*)NULL
,
189 _T("toolbar: can't insert NULL control") );
191 wxCHECK_MSG( control
->GetParent() == this, (wxToolBarToolBase
*)NULL
,
192 _T("control must have toolbar as parent") );
194 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
195 _T("invalid position in wxToolBar::InsertControl()") );
197 wxToolBarToolBase
*tool
= CreateTool(control
);
199 if ( !tool
|| !DoInsertTool(pos
, tool
) )
206 m_tools
.Insert(pos
, tool
);
211 wxToolBarToolBase
*wxToolBarBase::AddSeparator()
213 return InsertSeparator(GetToolsCount());
216 wxToolBarToolBase
*wxToolBarBase::InsertSeparator(size_t pos
)
218 wxCHECK_MSG( pos
<= GetToolsCount(), (wxToolBarToolBase
*)NULL
,
219 _T("invalid position in wxToolBar::InsertSeparator()") );
221 wxToolBarToolBase
*tool
= CreateTool(wxID_SEPARATOR
,
222 wxNullBitmap
, wxNullBitmap
,
223 FALSE
, (wxObject
*)NULL
,
224 wxEmptyString
, wxEmptyString
);
226 if ( !tool
|| !DoInsertTool(pos
, tool
) )
233 m_tools
.Insert(pos
, tool
);
238 wxToolBarToolBase
*wxToolBarBase::RemoveTool(int id
)
241 wxToolBarToolsList::Node
*node
;
242 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
244 if ( node
->GetData()->GetId() == id
)
252 // don't give any error messages - sometimes we might call RemoveTool()
253 // without knowing whether the tool is or not in the toolbar
254 return (wxToolBarToolBase
*)NULL
;
257 wxToolBarToolBase
*tool
= node
->GetData();
258 if ( !DoDeleteTool(pos
, tool
) )
260 return (wxToolBarToolBase
*)NULL
;
263 // the node would delete the data, so set it to NULL to avoid this
266 m_tools
.DeleteNode(node
);
271 bool wxToolBarBase::DeleteToolByPos(size_t pos
)
273 wxCHECK_MSG( pos
< GetToolsCount(), FALSE
,
274 _T("invalid position in wxToolBar::DeleteToolByPos()") );
276 wxToolBarToolsList::Node
*node
= m_tools
.Item(pos
);
278 if ( !DoDeleteTool(pos
, node
->GetData()) )
283 m_tools
.DeleteNode(node
);
288 bool wxToolBarBase::DeleteTool(int id
)
291 wxToolBarToolsList::Node
*node
;
292 for ( node
= m_tools
.GetFirst(); node
; node
= node
->GetNext() )
294 if ( node
->GetData()->GetId() == id
)
300 if ( !node
|| !DoDeleteTool(pos
, node
->GetData()) )
305 m_tools
.DeleteNode(node
);
310 wxToolBarToolBase
*wxToolBarBase::FindById(int id
) const
312 wxToolBarToolBase
*tool
= (wxToolBarToolBase
*)NULL
;
314 for ( wxToolBarToolsList::Node
*node
= m_tools
.GetFirst();
316 node
= node
->GetNext() )
318 tool
= node
->GetData();
319 if ( tool
->GetId() == id
)
331 void wxToolBarBase::ClearTools()
336 bool wxToolBarBase::Realize()
341 wxToolBarBase::~wxToolBarBase()
345 // ----------------------------------------------------------------------------
346 // wxToolBarBase tools state
347 // ----------------------------------------------------------------------------
349 void wxToolBarBase::EnableTool(int id
, bool enable
)
351 wxToolBarToolBase
*tool
= FindById(id
);
354 if ( tool
->Enable(enable
) )
356 DoEnableTool(tool
, enable
);
361 void wxToolBarBase::ToggleTool(int id
, bool toggle
)
363 wxToolBarToolBase
*tool
= FindById(id
);
364 if ( tool
&& tool
->CanBeToggled() )
366 if ( tool
->Toggle(toggle
) )
368 DoToggleTool(tool
, toggle
);
373 void wxToolBarBase::SetToggle(int id
, bool toggle
)
375 wxToolBarToolBase
*tool
= FindById(id
);
378 if ( tool
->SetToggle(toggle
) )
380 DoSetToggle(tool
, toggle
);
385 void wxToolBarBase::SetToolShortHelp(int id
, const wxString
& help
)
387 wxToolBarToolBase
*tool
= FindById(id
);
390 (void)tool
->SetShortHelp(help
);
394 void wxToolBarBase::SetToolLongHelp(int id
, const wxString
& help
)
396 wxToolBarToolBase
*tool
= FindById(id
);
399 (void)tool
->SetLongHelp(help
);
403 wxObject
*wxToolBarBase::GetToolClientData(int id
) const
405 wxToolBarToolBase
*tool
= FindById(id
);
407 return tool
? tool
->GetClientData() : (wxObject
*)NULL
;
410 void wxToolBarBase::SetToolClientData(int id
, wxObject
*clientData
)
412 wxToolBarToolBase
*tool
= FindById(id
);
414 wxCHECK_RET( tool
, _T("no such tool in wxToolBar::SetToolClientData") );
416 tool
->SetClientData(clientData
);
419 bool wxToolBarBase::GetToolState(int id
) const
421 wxToolBarToolBase
*tool
= FindById(id
);
422 wxCHECK_MSG( tool
, FALSE
, _T("no such tool") );
424 return tool
->IsToggled();
427 bool wxToolBarBase::GetToolEnabled(int id
) const
429 wxToolBarToolBase
*tool
= FindById(id
);
430 wxCHECK_MSG( tool
, FALSE
, _T("no such tool") );
432 return tool
->IsEnabled();
435 wxString
wxToolBarBase::GetToolShortHelp(int id
) const
437 wxToolBarToolBase
*tool
= FindById(id
);
438 wxCHECK_MSG( tool
, _T(""), _T("no such tool") );
440 return tool
->GetShortHelp();
443 wxString
wxToolBarBase::GetToolLongHelp(int id
) const
445 wxToolBarToolBase
*tool
= FindById(id
);
446 wxCHECK_MSG( tool
, _T(""), _T("no such tool") );
448 return tool
->GetLongHelp();
451 // ----------------------------------------------------------------------------
452 // wxToolBarBase geometry
453 // ----------------------------------------------------------------------------
455 void wxToolBarBase::SetMargins(int x
, int y
)
461 void wxToolBarBase::SetRows(int WXUNUSED(nRows
))
466 // ----------------------------------------------------------------------------
468 // ----------------------------------------------------------------------------
470 // Only allow toggle if returns TRUE
471 bool wxToolBarBase::OnLeftClick(int id
, bool toggleDown
)
473 wxCommandEvent
event(wxEVT_COMMAND_TOOL_CLICKED
, id
);
474 event
.SetEventObject(this);
476 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown
477 event
.SetInt((int)toggleDown
);
479 // and SetExtraLong() for backwards compatibility
480 event
.SetExtraLong((long)toggleDown
);
482 // Send events to this toolbar instead (and thence up the window hierarchy)
483 GetEventHandler()->ProcessEvent(event
);
488 // Call when right button down.
489 void wxToolBarBase::OnRightClick(int id
,
493 wxCommandEvent
event(wxEVT_COMMAND_TOOL_RCLICKED
, id
);
494 event
.SetEventObject(this);
497 GetEventHandler()->ProcessEvent(event
);
500 // Called when the mouse cursor enters a tool bitmap (no button pressed).
501 // Argument is -1 if mouse is exiting the toolbar.
502 // Note that for this event, the id of the window is used,
503 // and the integer parameter of wxCommandEvent is used to retrieve
505 void wxToolBarBase::OnMouseEnter(int id
)
507 wxCommandEvent
event(wxEVT_COMMAND_TOOL_ENTER
, GetId());
508 event
.SetEventObject(this);
511 (void)GetEventHandler()->ProcessEvent(event
);
513 wxToolBarToolBase
*tool
= FindById(id
);
514 if ( !tool
|| !tool
->GetLongHelp() )
517 wxFrame
*frame
= wxDynamicCast(GetParent(), wxFrame
);
521 frame
->SetStatusText(tool
->GetLongHelp());
524 // ----------------------------------------------------------------------------
526 // ----------------------------------------------------------------------------
528 void wxToolBarBase::OnIdle(wxIdleEvent
& event
)
535 // Do the toolbar button updates (check for EVT_UPDATE_UI handlers)
536 void wxToolBarBase::DoToolbarUpdates()
538 wxWindow
* parent
= this;
539 while (parent
->GetParent())
540 parent
= parent
->GetParent();
543 wxWindow
* focusWin
= wxFindFocusDescendant(parent
);
545 wxWindow
* focusWin
= (wxWindow
*) NULL
;
548 wxEvtHandler
* evtHandler
= focusWin
? focusWin
->GetEventHandler() : GetEventHandler() ;
550 for ( wxToolBarToolsList::Node
* node
= m_tools
.GetFirst();
552 node
= node
->GetNext() )
554 int id
= node
->GetData()->GetId();
556 wxUpdateUIEvent
event(id
);
557 event
.SetEventObject(this);
559 if ( evtHandler
->ProcessEvent(event
) )
561 if ( event
.GetSetEnabled() )
562 EnableTool(id
, event
.GetEnabled());
563 if ( event
.GetSetChecked() )
564 ToggleTool(id
, event
.GetChecked());
566 if ( event
.GetSetText() )
573 ///////////// button-label rendering helpers //////////////////
575 #define MIN_COLOR_DIFF 10
577 #define IS_IN_ARRAY(x,y) ( (x) < width && (y) < height && (x) >= 0 && (y) >= 0 )
579 #define IS_GREATER(red1,green1,blue1, red2,green2,blue2) ( ( red1 > red2 + MIN_COLOR_DIFF ) && \
580 ( green1 > green2 + MIN_COLOR_DIFF ) && \
581 ( blue1 > blue2 + MIN_COLOR_DIFF ) \
584 // Helper function, used by wxCreateGreyedImage
586 static void wxGreyOutImage( const wxImage
& src
, wxImage
& dest
,
587 const wxColour
& darkCol
, const wxColour
& lightCol
, const wxColour
& bgCol
)
589 // Second attempt, just making things monochrome
590 int width
= src
.GetWidth();
591 int height
= src
.GetHeight();
593 unsigned int redCur
, greenCur
, blueCur
;
596 for (x
= 0; x
< width
; x
++)
598 for (y
= 1; y
< height
; y
++)
600 redCur
= src
.GetRed(x
, y
);
601 greenCur
= src
.GetGreen(x
, y
);
602 blueCur
= src
.GetBlue(x
, y
);
604 // Change light things to the background colour
605 if ( redCur
>= (lightCol
.Red() - 50) && greenCur
>= (lightCol
.Green() - 50) && blueCur
>= (lightCol
.Blue() - 50) )
607 dest
.SetRGB(x
,y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue());
609 else if ( redCur
== bgCol
.Red() && greenCur
== bgCol
.Green() && blueCur
== bgCol
.Blue() )
611 // Leave the background colour as-is
612 // dest.SetRGB(x,y, bgCol.Red(), bgCol.Green(), bgCol.Blue());
614 else // if ( redCur <= darkCol.Red() && greenCur <= darkCol.Green() && blueCur <= darkCol.Blue() )
616 // Change dark things to really dark
617 dest
.SetRGB(x
,y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue());
623 // First attempt, causes problems with scissors icon
628 int width
= src
.GetWidth();
629 int height
= src
.GetHeight();
631 unsigned int redCur
, greenCur
, blueCur
;
635 redCur
= src
.GetRed(x
, y
);
636 greenCur
= src
.GetGreen(x
, y
);
637 blueCur
= src
.GetBlue(x
, y
);
639 if ( IS_IN_ARRAY(x
-1,y
-1) )
641 unsigned int redUpper
= src
.GetRed(x
-1, y
-1);
642 unsigned int greenUpper
= src
.GetGreen(x
-1, y
-1);
643 unsigned int blueUpper
= src
.GetBlue(x
-1, y
-1);
645 // if the upper element is lighter than current
646 if ( IS_GREATER(redUpper
, greenUpper
, blueUpper
, redCur
, greenCur
, blueCur
) )
648 dest
.SetRGB(x
,y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue());
650 // if the current element is ligher than the upper
651 else if ( IS_GREATER(redCur
, greenCur
, blueCur
, redUpper
, greenUpper
, blueUpper
) )
653 dest
.SetRGB(x
,y
, lightCol
.Red(), lightCol
.Green(), lightCol
.Blue());
657 unsigned int red1
= dest
.GetRed(x
-1, y
-1);
658 unsigned int green1
= dest
.GetGreen(x
-1, y
-1);
659 unsigned int blue1
= dest
.GetBlue(x
-1, y
-1);
661 if ( red1
== lightCol
.Red() && green1
== lightCol
.Green() && blue1
== lightCol
.Blue() )
662 dest
.SetRGB(x
, y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue());
663 else if ( red1
== darkCol
.Red() && green1
== darkCol
.Green() && blue1
== darkCol
.Blue() )
664 dest
.SetRGB(x
, y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue());
666 dest
.SetRGB(x
, y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue());
672 if ( IS_IN_ARRAY(x
+1,y
-1) )
679 while ( IS_IN_ARRAY(x
-1,y
+1) )
685 if ( IS_IN_ARRAY(x
,y
+1) )
692 if ( IS_IN_ARRAY(x
+1,y
) )
706 * Make a greyed-out image suitable for disabled buttons.
707 * This code is adapted from wxNewBitmapButton in FL.
710 bool wxCreateGreyedImage(const wxImage
& in
, wxImage
& out
)
714 // assuming the pixels along the edges are of the background color
715 wxColour
bgCol(in
.GetRed(0, 0), in
.GetGreen(0, 0), in
.GetBlue(0, 0));
717 wxColour darkCol
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
) ;
718 wxColour lightCol
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
) ;
720 wxGreyOutImage(in
, out
, darkCol
, lightCol
, bgCol
);
725 #endif // wxUSE_TOOLBAR