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) 6// Created: 04/01/98 7// RCS-ID: $Id: tbarbase.cpp 42840 2006-10-31 13:09:08Z VZ $ 8// Copyright: (c) Julian Smart 9// Licence: wxWindows licence 10///////////////////////////////////////////////////////////////////////////// 11 12// ============================================================================ 13// declarations 14// ============================================================================ 15 16// ---------------------------------------------------------------------------- 17// headers 18// ---------------------------------------------------------------------------- 19 20// For compilers that support precompilation, includes "wx.h". 21#include "wx/wxprec.h" 22 23#ifdef __BORLANDC__ 24 #pragma hdrstop 25#endif 26 27#if wxUSE_TOOLBAR 28 29#include "wx/toolbar.h" 30 31#ifndef WX_PRECOMP 32 #include "wx/control.h" 33 #include "wx/frame.h" 34 #include "wx/settings.h" 35 #include "wx/image.h" 36#endif 37 38// ---------------------------------------------------------------------------- 39// wxWidgets macros 40// ---------------------------------------------------------------------------- 41 42BEGIN_EVENT_TABLE(wxToolBarBase, wxControl) 43END_EVENT_TABLE() 44 45#include "wx/listimpl.cpp" 46 47WX_DEFINE_LIST(wxToolBarToolsList) 48 49// ============================================================================ 50// implementation 51// ============================================================================ 52 53// ---------------------------------------------------------------------------- 54// wxToolBarToolBase 55// ---------------------------------------------------------------------------- 56 57IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject) 58 59bool wxToolBarToolBase::Enable(bool enable) 60{ 61 if ( m_enabled == enable ) 62 return false; 63 64 m_enabled = enable; 65 66 return true; 67} 68 69bool wxToolBarToolBase::Toggle(bool toggle) 70{ 71 wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") ); 72 73 if ( m_toggled == toggle ) 74 return false; 75 76 m_toggled = toggle; 77 78 return true; 79} 80 81bool wxToolBarToolBase::SetToggle(bool toggle) 82{ 83 wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL; 84 if ( m_kind == kind ) 85 return false; 86 87 m_kind = kind; 88 89 return true; 90} 91 92bool wxToolBarToolBase::SetShortHelp(const wxString& help) 93{ 94 if ( m_shortHelpString == help ) 95 return false; 96 97 m_shortHelpString = help; 98 99 return true; 100} 101 102bool wxToolBarToolBase::SetLongHelp(const wxString& help) 103{ 104 if ( m_longHelpString == help ) 105 return false; 106 107 m_longHelpString = help; 108 109 return true; 110} 111 112// ---------------------------------------------------------------------------- 113// wxToolBarBase adding/deleting items 114// ---------------------------------------------------------------------------- 115 116wxToolBarBase::wxToolBarBase() 117{ 118 // the list owns the pointers 119 m_xMargin = m_yMargin = 0; 120 m_maxRows = m_maxCols = 0; 121 m_toolPacking = m_toolSeparation = 0; 122 m_defaultWidth = 16; 123 m_defaultHeight = 15; 124} 125 126void wxToolBarBase::FixupStyle() 127{ 128 if ( !HasFlag(wxTB_TOP | wxTB_LEFT | wxTB_RIGHT | wxTB_BOTTOM) ) 129 { 130 // this is the default 131 m_windowStyle |= wxTB_TOP; 132 } 133} 134 135wxToolBarToolBase *wxToolBarBase::DoAddTool(int id, 136 const wxString& label, 137 const wxBitmap& bitmap, 138 const wxBitmap& bmpDisabled, 139 wxItemKind kind, 140 const wxString& shortHelp, 141 const wxString& longHelp, 142 wxObject *clientData, 143 wxCoord WXUNUSED(xPos), 144 wxCoord WXUNUSED(yPos)) 145{ 146 InvalidateBestSize(); 147 return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled, 148 kind, shortHelp, longHelp, clientData); 149} 150 151wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos, 152 int id, 153 const wxString& label, 154 const wxBitmap& bitmap, 155 const wxBitmap& bmpDisabled, 156 wxItemKind kind, 157 const wxString& shortHelp, 158 const wxString& longHelp, 159 wxObject *clientData) 160{ 161 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, 162 _T("invalid position in wxToolBar::InsertTool()") ); 163 164 wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind, 165 clientData, shortHelp, longHelp); 166 167 if ( !InsertTool(pos, tool) ) 168 { 169 delete tool; 170 171 return NULL; 172 } 173 174 return tool; 175} 176 177wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool) 178{ 179 return InsertTool(GetToolsCount(), tool); 180} 181 182wxToolBarToolBase * 183wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool) 184{ 185 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, 186 _T("invalid position in wxToolBar::InsertTool()") ); 187 188 if ( !tool || !DoInsertTool(pos, tool) ) 189 { 190 return NULL; 191 } 192 193 m_tools.Insert(pos, tool); 194 195 return tool; 196} 197 198wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control) 199{ 200 return InsertControl(GetToolsCount(), control); 201} 202 203wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control) 204{ 205 wxCHECK_MSG( control, (wxToolBarToolBase *)NULL, 206 _T("toolbar: can't insert NULL control") ); 207 208 wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL, 209 _T("control must have toolbar as parent") ); 210 211 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, 212 _T("invalid position in wxToolBar::InsertControl()") ); 213 214 wxToolBarToolBase *tool = CreateTool(control); 215 216 if ( !InsertTool(pos, tool) ) 217 { 218 delete tool; 219 220 return NULL; 221 } 222 223 return tool; 224} 225 226wxControl *wxToolBarBase::FindControl( int id ) 227{ 228 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 229 node; 230 node = node->GetNext() ) 231 { 232 const wxToolBarToolBase * const tool = node->GetData(); 233 if ( tool->IsControl() ) 234 { 235 wxControl * const control = tool->GetControl(); 236 237 if ( !control ) 238 { 239 wxFAIL_MSG( _T("NULL control in toolbar?") ); 240 } 241 else if ( control->GetId() == id ) 242 { 243 // found 244 return control; 245 } 246 } 247 } 248 249 return NULL; 250} 251 252wxToolBarToolBase *wxToolBarBase::AddSeparator() 253{ 254 return InsertSeparator(GetToolsCount()); 255} 256 257wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos) 258{ 259 wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, 260 _T("invalid position in wxToolBar::InsertSeparator()") ); 261 262 wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR, 263 wxEmptyString, 264 wxNullBitmap, wxNullBitmap, 265 wxITEM_SEPARATOR, (wxObject *)NULL, 266 wxEmptyString, wxEmptyString); 267 268 if ( !tool || !DoInsertTool(pos, tool) ) 269 { 270 delete tool; 271 272 return NULL; 273 } 274 275 m_tools.Insert(pos, tool); 276 277 return tool; 278} 279 280wxToolBarToolBase *wxToolBarBase::RemoveTool(int id) 281{ 282 size_t pos = 0; 283 wxToolBarToolsList::compatibility_iterator node; 284 for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) 285 { 286 if ( node->GetData()->GetId() == id ) 287 break; 288 289 pos++; 290 } 291 292 if ( !node ) 293 { 294 // don't give any error messages - sometimes we might call RemoveTool() 295 // without knowing whether the tool is or not in the toolbar 296 return (wxToolBarToolBase *)NULL; 297 } 298 299 wxToolBarToolBase *tool = node->GetData(); 300 if ( !DoDeleteTool(pos, tool) ) 301 { 302 return (wxToolBarToolBase *)NULL; 303 } 304 305 m_tools.Erase(node); 306 307 return tool; 308} 309 310bool wxToolBarBase::DeleteToolByPos(size_t pos) 311{ 312 wxCHECK_MSG( pos < GetToolsCount(), false, 313 _T("invalid position in wxToolBar::DeleteToolByPos()") ); 314 315 wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos); 316 317 if ( !DoDeleteTool(pos, node->GetData()) ) 318 { 319 return false; 320 } 321 322 delete node->GetData(); 323 m_tools.Erase(node); 324 325 return true; 326} 327 328bool wxToolBarBase::DeleteTool(int id) 329{ 330 size_t pos = 0; 331 wxToolBarToolsList::compatibility_iterator node; 332 for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) 333 { 334 if ( node->GetData()->GetId() == id ) 335 break; 336 337 pos++; 338 } 339 340 if ( !node || !DoDeleteTool(pos, node->GetData()) ) 341 { 342 return false; 343 } 344 345 delete node->GetData(); 346 m_tools.Erase(node); 347 348 return true; 349} 350 351wxToolBarToolBase *wxToolBarBase::FindById(int id) const 352{ 353 wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL; 354 355 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 356 node; 357 node = node->GetNext() ) 358 { 359 tool = node->GetData(); 360 if ( tool->GetId() == id ) 361 { 362 // found 363 break; 364 } 365 366 tool = NULL; 367 } 368 369 return tool; 370} 371 372void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool) 373{ 374 wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") ); 375 376 if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) 377 return; 378 379 wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool); 380 wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") ); 381 382 wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext(); 383 while ( nodeNext ) 384 { 385 wxToolBarToolBase *toolNext = nodeNext->GetData(); 386 387 if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) 388 break; 389 390 if ( toolNext->Toggle(false) ) 391 { 392 DoToggleTool(toolNext, false); 393 } 394 395 nodeNext = nodeNext->GetNext(); 396 } 397 398 wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); 399 while ( nodePrev ) 400 { 401 wxToolBarToolBase *toolNext = nodePrev->GetData(); 402 403 if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) 404 break; 405 406 if ( toolNext->Toggle(false) ) 407 { 408 DoToggleTool(toolNext, false); 409 } 410 411 nodePrev = nodePrev->GetPrevious(); 412 } 413} 414 415void wxToolBarBase::ClearTools() 416{ 417 while ( GetToolsCount() ) 418 { 419 DeleteToolByPos(0); 420 } 421} 422 423bool wxToolBarBase::Realize() 424{ 425 return true; 426} 427 428wxToolBarBase::~wxToolBarBase() 429{ 430 WX_CLEAR_LIST(wxToolBarToolsList, m_tools); 431 432 // notify the frame that it doesn't have a tool bar any longer to avoid 433 // dangling pointers 434 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); 435 if ( frame && frame->GetToolBar() == this ) 436 { 437 frame->SetToolBar(NULL); 438 } 439} 440 441// ---------------------------------------------------------------------------- 442// wxToolBarBase tools state 443// ---------------------------------------------------------------------------- 444 445void wxToolBarBase::EnableTool(int id, bool enable) 446{ 447 wxToolBarToolBase *tool = FindById(id); 448 if ( tool ) 449 { 450 if ( tool->Enable(enable) ) 451 { 452 DoEnableTool(tool, enable); 453 } 454 } 455} 456 457void wxToolBarBase::ToggleTool(int id, bool toggle) 458{ 459 wxToolBarToolBase *tool = FindById(id); 460 if ( tool && tool->CanBeToggled() ) 461 { 462 if ( tool->Toggle(toggle) ) 463 { 464 UnToggleRadioGroup(tool); 465 DoToggleTool(tool, toggle); 466 } 467 } 468} 469 470void wxToolBarBase::SetToggle(int id, bool toggle) 471{ 472 wxToolBarToolBase *tool = FindById(id); 473 if ( tool ) 474 { 475 if ( tool->SetToggle(toggle) ) 476 { 477 DoSetToggle(tool, toggle); 478 } 479 } 480} 481 482void wxToolBarBase::SetToolShortHelp(int id, const wxString& help) 483{ 484 wxToolBarToolBase *tool = FindById(id); 485 if ( tool ) 486 { 487 (void)tool->SetShortHelp(help); 488 } 489} 490 491void wxToolBarBase::SetToolLongHelp(int id, const wxString& help) 492{ 493 wxToolBarToolBase *tool = FindById(id); 494 if ( tool ) 495 { 496 (void)tool->SetLongHelp(help); 497 } 498} 499 500wxObject *wxToolBarBase::GetToolClientData(int id) const 501{ 502 wxToolBarToolBase *tool = FindById(id); 503 504 return tool ? tool->GetClientData() : (wxObject *)NULL; 505} 506 507void wxToolBarBase::SetToolClientData(int id, wxObject *clientData) 508{ 509 wxToolBarToolBase *tool = FindById(id); 510 511 wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") ); 512 513 tool->SetClientData(clientData); 514} 515 516int wxToolBarBase::GetToolPos(int id) const 517{ 518 size_t pos = 0; 519 wxToolBarToolsList::compatibility_iterator node; 520 521 for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) 522 { 523 if ( node->GetData()->GetId() == id ) 524 return pos; 525 526 pos++; 527 } 528 529 return wxNOT_FOUND; 530} 531 532bool wxToolBarBase::GetToolState(int id) const 533{ 534 wxToolBarToolBase *tool = FindById(id); 535 wxCHECK_MSG( tool, false, _T("no such tool") ); 536 537 return tool->IsToggled(); 538} 539 540bool wxToolBarBase::GetToolEnabled(int id) const 541{ 542 wxToolBarToolBase *tool = FindById(id); 543 wxCHECK_MSG( tool, false, _T("no such tool") ); 544 545 return tool->IsEnabled(); 546} 547 548wxString wxToolBarBase::GetToolShortHelp(int id) const 549{ 550 wxToolBarToolBase *tool = FindById(id); 551 wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); 552 553 return tool->GetShortHelp(); 554} 555 556wxString wxToolBarBase::GetToolLongHelp(int id) const 557{ 558 wxToolBarToolBase *tool = FindById(id); 559 wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); 560 561 return tool->GetLongHelp(); 562} 563 564// ---------------------------------------------------------------------------- 565// wxToolBarBase geometry 566// ---------------------------------------------------------------------------- 567 568void wxToolBarBase::SetMargins(int x, int y) 569{ 570 m_xMargin = x; 571 m_yMargin = y; 572} 573 574void wxToolBarBase::SetRows(int WXUNUSED(nRows)) 575{ 576 // nothing 577} 578 579// ---------------------------------------------------------------------------- 580// event processing 581// ---------------------------------------------------------------------------- 582 583// Only allow toggle if returns true 584bool wxToolBarBase::OnLeftClick(int id, bool toggleDown) 585{ 586 wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id); 587 event.SetEventObject(this); 588 589 // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown 590 event.SetInt((int)toggleDown); 591 592 // and SetExtraLong() for backwards compatibility 593 event.SetExtraLong((long)toggleDown); 594 595 // Send events to this toolbar instead (and thence up the window hierarchy) 596 GetEventHandler()->ProcessEvent(event); 597 598 return true; 599} 600 601// Call when right button down. 602void wxToolBarBase::OnRightClick(int id, 603 long WXUNUSED(x), 604 long WXUNUSED(y)) 605{ 606 wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id); 607 event.SetEventObject(this); 608 event.SetInt(id); 609 610 GetEventHandler()->ProcessEvent(event); 611} 612 613// Called when the mouse cursor enters a tool bitmap (no button pressed). 614// Argument is wxID_ANY if mouse is exiting the toolbar. 615// Note that for this event, the id of the window is used, 616// and the integer parameter of wxCommandEvent is used to retrieve 617// the tool id. 618void wxToolBarBase::OnMouseEnter(int id) 619{ 620 wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId()); 621 event.SetEventObject(this); 622 event.SetInt(id); 623 624 wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); 625 if( frame ) 626 { 627 wxString help; 628 wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id); 629 if(tool) 630 help = tool->GetLongHelp(); 631 frame->DoGiveHelp( help, id != wxID_ANY ); 632 } 633 634 (void)GetEventHandler()->ProcessEvent(event); 635} 636 637// ---------------------------------------------------------------------------- 638// UI updates 639// ---------------------------------------------------------------------------- 640 641// Do the toolbar button updates (check for EVT_UPDATE_UI handlers) 642void wxToolBarBase::UpdateWindowUI(long flags) 643{ 644 wxWindowBase::UpdateWindowUI(flags); 645 646 // There is no sense in updating the toolbar UI 647 // if the parent window is about to get destroyed 648 wxWindow *tlw = wxGetTopLevelParent( this ); 649 if (tlw && wxPendingDelete.Member( tlw )) 650 return; 651 652 wxEvtHandler* evtHandler = GetEventHandler() ; 653 654 for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); 655 node; 656 node = node->GetNext() ) 657 { 658 int id = node->GetData()->GetId(); 659 660 wxUpdateUIEvent event(id); 661 event.SetEventObject(this); 662 663 if ( evtHandler->ProcessEvent(event) ) 664 { 665 if ( event.GetSetEnabled() ) 666 EnableTool(id, event.GetEnabled()); 667 if ( event.GetSetChecked() ) 668 ToggleTool(id, event.GetChecked()); 669#if 0 670 if ( event.GetSetText() ) 671 // Set tooltip? 672#endif // 0 673 } 674 } 675} 676 677#if wxUSE_IMAGE 678 679/* 680 * Make a greyed-out image suitable for disabled buttons. 681 * This code is adapted from wxNewBitmapButton in FL. 682 */ 683 684bool wxCreateGreyedImage(const wxImage& src, wxImage& dst) 685{ 686 dst = src.Copy(); 687 688 unsigned char rBg, gBg, bBg; 689 if ( src.HasMask() ) 690 { 691 src.GetOrFindMaskColour(&rBg, &gBg, &bBg); 692 dst.SetMaskColour(rBg, gBg, bBg); 693 } 694 else // assuming the pixels along the edges are of the background color 695 { 696 rBg = src.GetRed(0, 0); 697 gBg = src.GetGreen(0, 0); 698 bBg = src.GetBlue(0, 0); 699 } 700 701 const wxColour colBg(rBg, gBg, bBg); 702 703 const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); 704 const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); 705 706 // Second attempt, just making things monochrome 707 const int width = src.GetWidth(); 708 const int height = src.GetHeight(); 709 710 for ( int x = 0; x < width; x++ ) 711 { 712 for ( int y = 0; y < height; y++ ) 713 { 714 const int r = src.GetRed(x, y); 715 const int g = src.GetGreen(x, y); 716 const int b = src.GetBlue(x, y); 717 718 if ( r == rBg && g == gBg && b == bBg ) 719 { 720 // Leave the background colour as-is 721 continue; 722 } 723 724 // Change light things to the background colour 725 wxColour col; 726 if ( r >= (colLight.Red() - 50) && 727 g >= (colLight.Green() - 50) && 728 b >= (colLight.Blue() - 50) ) 729 { 730 col = colBg; 731 } 732 else // Change dark things to really dark 733 { 734 col = colDark; 735 } 736 737 dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue()); 738 } 739 } 740 741 return true; 742} 743 744#endif // wxUSE_IMAGE 745 746#endif // wxUSE_TOOLBAR 747