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
) 
 592     int width 
= src
.GetWidth(); 
 593     int height 
= src
.GetHeight(); 
 595     unsigned int redCur
, greenCur
, blueCur
; 
 599         redCur 
= src
.GetRed(x
, y
); 
 600         greenCur 
= src
.GetGreen(x
, y
); 
 601         blueCur 
= src
.GetBlue(x
, y
);      
 603         if ( IS_IN_ARRAY(x
-1,y
-1) ) 
 605             unsigned int redUpper 
= src
.GetRed(x
-1, y
-1); 
 606             unsigned int greenUpper 
= src
.GetGreen(x
-1, y
-1); 
 607             unsigned int blueUpper 
= src
.GetBlue(x
-1, y
-1);      
 609             // if the upper element is lighter than current 
 610             if ( IS_GREATER(redUpper
, greenUpper
, blueUpper
, redCur
, greenCur
, blueCur
) ) 
 612                 dest
.SetRGB(x
,y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue()); 
 614             // if the current element is ligher than the upper 
 615             else if ( IS_GREATER(redCur
, greenCur
, blueCur
, redUpper
, greenUpper
, blueUpper
) ) 
 617                 dest
.SetRGB(x
,y
, lightCol
.Red(), lightCol
.Green(), lightCol
.Blue()); 
 621                 unsigned int red1 
= dest
.GetRed(x
-1, y
-1); 
 622                 unsigned int green1 
= dest
.GetGreen(x
-1, y
-1); 
 623                 unsigned int blue1 
= dest
.GetBlue(x
-1, y
-1);      
 625                 if ( red1 
== lightCol
.Red() && green1 
== lightCol
.Green() && blue1 
== lightCol
.Blue() ) 
 626                     dest
.SetRGB(x
, y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue()); 
 627                 else if ( red1 
== darkCol
.Red() && green1 
== darkCol
.Green() && blue1 
== darkCol
.Blue() ) 
 628                     dest
.SetRGB(x
, y
, darkCol
.Red(), darkCol
.Green(), darkCol
.Blue()); 
 630                     dest
.SetRGB(x
, y
, bgCol
.Red(), bgCol
.Green(), bgCol
.Blue()); 
 636         if ( IS_IN_ARRAY(x
+1,y
-1) )  
 643             while ( IS_IN_ARRAY(x
-1,y
+1) )  
 649             if ( IS_IN_ARRAY(x
,y
+1) ) 
 656                 if ( IS_IN_ARRAY(x
+1,y
) ) 
 669  * Make a greyed-out image suitable for disabled buttons. 
 670  * This code is adapted from wxNewBitmapButton in FL. 
 673 bool wxCreateGreyedImage(const wxImage
& in
, wxImage
& out
) 
 677     // assuming the pixels along the edges are of the background color 
 678     wxColour 
bgCol(in
.GetRed(0, 0), in
.GetGreen(0, 0), in
.GetBlue(0, 0)); 
 680     wxColour darkCol 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW
) ; 
 681     wxColour lightCol 
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT
) ; 
 683     wxGreyOutImage(in
, out
, darkCol
, lightCol
, bgCol
); 
 688 #endif // wxUSE_TOOLBAR