1///////////////////////////////////////////////////////////////////////////// 2// Name: src/common/sizer.cpp 3// Purpose: provide new wxSizer class for layout 4// Author: Robert Roebling and Robin Dunn, contributions by 5// Dirk Holtwick, Ron Lee 6// Modified by: Ron Lee 7// Created: 8// RCS-ID: $Id: sizer.cpp 66936 2011-02-17 09:52:57Z JS $ 9// Copyright: (c) Robin Dunn, Robert Roebling 10// Licence: wxWindows licence 11///////////////////////////////////////////////////////////////////////////// 12 13// For compilers that support precompilation, includes "wx.h". 14#include "wx/wxprec.h" 15 16#ifdef __BORLANDC__ 17 #pragma hdrstop 18#endif 19 20#include "wx/display.h" 21#include "wx/sizer.h" 22 23#ifndef WX_PRECOMP 24 #include "wx/string.h" 25 #include "wx/intl.h" 26 #include "wx/math.h" 27 #include "wx/utils.h" 28 #include "wx/settings.h" 29 #include "wx/button.h" 30 #include "wx/statbox.h" 31 #include "wx/toplevel.h" 32#endif // WX_PRECOMP 33 34#include "wx/listimpl.cpp" 35 36#if WXWIN_COMPATIBILITY_2_4 37 #include "wx/notebook.h" 38#endif 39 40//--------------------------------------------------------------------------- 41 42IMPLEMENT_CLASS(wxSizerItem, wxObject) 43IMPLEMENT_CLASS(wxSizer, wxObject) 44IMPLEMENT_CLASS(wxGridSizer, wxSizer) 45IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer) 46IMPLEMENT_CLASS(wxBoxSizer, wxSizer) 47#if wxUSE_STATBOX 48IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer) 49#endif 50#if wxUSE_BUTTON 51IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer) 52#endif 53 54WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) 55 56/* 57 TODO PROPERTIES 58 sizeritem 59 object 60 object_ref 61 minsize 62 option 63 flag 64 border 65 spacer 66 option 67 flag 68 borfder 69 boxsizer 70 orient 71 staticboxsizer 72 orient 73 label 74 gridsizer 75 rows 76 cols 77 vgap 78 hgap 79 flexgridsizer 80 rows 81 cols 82 vgap 83 hgap 84 growablerows 85 growablecols 86 minsize 87*/ 88 89 90// ---------------------------------------------------------------------------- 91// wxSizerFlags 92// ---------------------------------------------------------------------------- 93 94wxSizerFlags& wxSizerFlags::ReserveSpaceEvenIfHidden() 95{ 96 m_flags |= wxRESERVE_SPACE_EVEN_IF_HIDDEN; 97 return *this; 98} 99 100// ---------------------------------------------------------------------------- 101// wxSizerItem 102// ---------------------------------------------------------------------------- 103 104void wxSizerItem::Init(const wxSizerFlags& flags) 105{ 106 Init(); 107 108 m_proportion = flags.GetProportion(); 109 m_flag = flags.GetFlags(); 110 m_border = flags.GetBorderInPixels(); 111} 112 113wxSizerItem::wxSizerItem() 114{ 115 Init(); 116 117 m_proportion = 0; 118 m_border = 0; 119 m_flag = 0; 120 121 m_kind = Item_None; 122} 123 124// window item 125void wxSizerItem::SetWindow(wxWindow *window) 126{ 127 wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") ); 128 129 m_kind = Item_Window; 130 m_window = window; 131 132 // window doesn't become smaller than its initial size, whatever happens 133 m_minSize = window->GetSize(); 134 135 if ( m_flag & wxFIXED_MINSIZE ) 136 window->SetMinSize(m_minSize); 137 138 // aspect ratio calculated from initial size 139 SetRatio(m_minSize); 140} 141 142wxSizerItem::wxSizerItem(wxWindow *window, 143 int proportion, 144 int flag, 145 int border, 146 wxObject* userData) 147 : m_proportion(proportion), 148 m_border(border), 149 m_flag(flag), 150 m_userData(userData) 151{ 152 SetWindow(window); 153} 154 155// sizer item 156void wxSizerItem::SetSizer(wxSizer *sizer) 157{ 158 m_kind = Item_Sizer; 159 m_sizer = sizer; 160} 161 162wxSizerItem::wxSizerItem(wxSizer *sizer, 163 int proportion, 164 int flag, 165 int border, 166 wxObject* userData) 167 : m_proportion(proportion), 168 m_border(border), 169 m_flag(flag), 170 m_ratio(0.0), 171 m_userData(userData) 172{ 173 SetSizer(sizer); 174 175 // m_minSize is set later 176} 177 178// spacer item 179void wxSizerItem::SetSpacer(const wxSize& size) 180{ 181 m_kind = Item_Spacer; 182 m_spacer = new wxSizerSpacer(size); 183 m_minSize = size; 184 SetRatio(size); 185} 186 187wxSizerItem::wxSizerItem(int width, 188 int height, 189 int proportion, 190 int flag, 191 int border, 192 wxObject* userData) 193 : m_minSize(width, height), // minimal size is the initial size 194 m_proportion(proportion), 195 m_border(border), 196 m_flag(flag), 197 m_userData(userData) 198{ 199 SetSpacer(width, height); 200} 201 202wxSizerItem::~wxSizerItem() 203{ 204 delete m_userData; 205 206 switch ( m_kind ) 207 { 208 case Item_None: 209 break; 210 211 case Item_Window: 212 m_window->SetContainingSizer(NULL); 213 break; 214 215 case Item_Sizer: 216 delete m_sizer; 217 break; 218 219 case Item_Spacer: 220 delete m_spacer; 221 break; 222 223 case Item_Max: 224 default: 225 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 226 } 227} 228 229wxSize wxSizerItem::GetSpacer() const 230{ 231 wxSize size; 232 if ( m_kind == Item_Spacer ) 233 size = m_spacer->GetSize(); 234 235 return size; 236} 237 238 239wxSize wxSizerItem::GetSize() const 240{ 241 wxSize ret; 242 switch ( m_kind ) 243 { 244 case Item_None: 245 break; 246 247 case Item_Window: 248 ret = m_window->GetSize(); 249 break; 250 251 case Item_Sizer: 252 ret = m_sizer->GetSize(); 253 break; 254 255 case Item_Spacer: 256 ret = m_spacer->GetSize(); 257 break; 258 259 case Item_Max: 260 default: 261 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 262 } 263 264 if (m_flag & wxWEST) 265 ret.x += m_border; 266 if (m_flag & wxEAST) 267 ret.x += m_border; 268 if (m_flag & wxNORTH) 269 ret.y += m_border; 270 if (m_flag & wxSOUTH) 271 ret.y += m_border; 272 273 return ret; 274} 275 276wxSize wxSizerItem::CalcMin() 277{ 278 if (IsSizer()) 279 { 280 m_minSize = m_sizer->GetMinSize(); 281 282 // if we have to preserve aspect ratio _AND_ this is 283 // the first-time calculation, consider ret to be initial size 284 if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) ) 285 SetRatio(m_minSize); 286 } 287 else if ( IsWindow() ) 288 { 289 // Since the size of the window may change during runtime, we 290 // should use the current minimal/best size. 291 m_minSize = m_window->GetEffectiveMinSize(); 292 } 293 294 return GetMinSizeWithBorder(); 295} 296 297wxSize wxSizerItem::GetMinSizeWithBorder() const 298{ 299 wxSize ret = m_minSize; 300 301 if (m_flag & wxWEST) 302 ret.x += m_border; 303 if (m_flag & wxEAST) 304 ret.x += m_border; 305 if (m_flag & wxNORTH) 306 ret.y += m_border; 307 if (m_flag & wxSOUTH) 308 ret.y += m_border; 309 310 return ret; 311} 312 313 314void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ ) 315{ 316 wxPoint pos = pos_; 317 wxSize size = size_; 318 if (m_flag & wxSHAPED) 319 { 320 // adjust aspect ratio 321 int rwidth = (int) (size.y * m_ratio); 322 if (rwidth > size.x) 323 { 324 // fit horizontally 325 int rheight = (int) (size.x / m_ratio); 326 // add vertical space 327 if (m_flag & wxALIGN_CENTER_VERTICAL) 328 pos.y += (size.y - rheight) / 2; 329 else if (m_flag & wxALIGN_BOTTOM) 330 pos.y += (size.y - rheight); 331 // use reduced dimensions 332 size.y =rheight; 333 } 334 else if (rwidth < size.x) 335 { 336 // add horizontal space 337 if (m_flag & wxALIGN_CENTER_HORIZONTAL) 338 pos.x += (size.x - rwidth) / 2; 339 else if (m_flag & wxALIGN_RIGHT) 340 pos.x += (size.x - rwidth); 341 size.x = rwidth; 342 } 343 } 344 345 // This is what GetPosition() returns. Since we calculate 346 // borders afterwards, GetPosition() will be the left/top 347 // corner of the surrounding border. 348 m_pos = pos; 349 350 if (m_flag & wxWEST) 351 { 352 pos.x += m_border; 353 size.x -= m_border; 354 } 355 if (m_flag & wxEAST) 356 { 357 size.x -= m_border; 358 } 359 if (m_flag & wxNORTH) 360 { 361 pos.y += m_border; 362 size.y -= m_border; 363 } 364 if (m_flag & wxSOUTH) 365 { 366 size.y -= m_border; 367 } 368 369 if (size.x < 0) 370 size.x = 0; 371 if (size.y < 0) 372 size.y = 0; 373 374 m_rect = wxRect(pos, size); 375 376 switch ( m_kind ) 377 { 378 case Item_None: 379 wxFAIL_MSG( _T("can't set size of uninitialized sizer item") ); 380 break; 381 382 case Item_Window: 383 m_window->SetSize(pos.x, pos.y, size.x, size.y, 384 wxSIZE_ALLOW_MINUS_ONE); 385 break; 386 387 case Item_Sizer: 388 m_sizer->SetDimension(pos.x, pos.y, size.x, size.y); 389 break; 390 391 case Item_Spacer: 392 m_spacer->SetSize(size); 393 break; 394 395 case Item_Max: 396 default: 397 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 398 } 399} 400 401void wxSizerItem::DeleteWindows() 402{ 403 switch ( m_kind ) 404 { 405 case Item_None: 406 case Item_Spacer: 407 break; 408 409 case Item_Window: 410 //We are deleting the window from this sizer - normally 411 //the window destroys the sizer associated with it, 412 //which might destroy this, which we don't want 413 m_window->SetContainingSizer(NULL); 414 m_window->Destroy(); 415 //Putting this after the switch will result in a spacer 416 //not being deleted properly on destruction 417 m_kind = Item_None; 418 break; 419 420 case Item_Sizer: 421 m_sizer->DeleteWindows(); 422 break; 423 424 case Item_Max: 425 default: 426 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 427 } 428 429} 430 431void wxSizerItem::Show( bool show ) 432{ 433 switch ( m_kind ) 434 { 435 case Item_None: 436 wxFAIL_MSG( _T("can't show uninitialized sizer item") ); 437 break; 438 439 case Item_Window: 440 m_window->Show(show); 441 break; 442 443 case Item_Sizer: 444 m_sizer->Show(show); 445 break; 446 447 case Item_Spacer: 448 m_spacer->Show(show); 449 break; 450 451 case Item_Max: 452 default: 453 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 454 } 455} 456 457bool wxSizerItem::IsShown() const 458{ 459 switch ( m_kind ) 460 { 461 case Item_None: 462 // we may be called from CalcMin(), just return false so that we're 463 // not used 464 break; 465 466 case Item_Window: 467 return m_window->IsShown(); 468 469 case Item_Sizer: 470 // arbitrarily decide that if at least one of our elements is 471 // shown, so are we (this arbitrariness is the reason for 472 // deprecating this function) 473 { 474 // Some apps (such as dialog editors) depend on an empty sizer still 475 // being laid out correctly and reporting the correct size and position. 476 if (m_sizer->GetChildren().GetCount() == 0) 477 return true; 478 479 for ( wxSizerItemList::compatibility_iterator 480 node = m_sizer->GetChildren().GetFirst(); 481 node; 482 node = node->GetNext() ) 483 { 484 if ( node->GetData()->IsShown() ) 485 return true; 486 } 487 } 488 return false; 489 490 case Item_Spacer: 491 return m_spacer->IsShown(); 492 493 case Item_Max: 494 default: 495 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); 496 } 497 498 return false; 499} 500 501// This is a helper to support wxRESERVE_SPACE_EVEN_IF_HIDDEN. In wx 2.9+, 502// this flag is respected by IsShown(), but not in wx 2.8. 503bool wxSizerItem::ShouldAccountFor() const 504{ 505 if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN ) 506 return true; 507 508 if ( IsSizer() ) 509 { 510 // this mirrors wxSizerItem::IsShown() code above 511 const wxSizerItemList& children = m_sizer->GetChildren(); 512 if ( children.GetCount() == 0 ) 513 return true; 514 515 for ( wxSizerItemList::compatibility_iterator 516 node = children.GetFirst(); 517 node; 518 node = node->GetNext() ) 519 { 520 if ( node->GetData()->ShouldAccountFor() ) 521 return true; 522 } 523 return false; 524 } 525 else 526 { 527 return IsShown(); 528 } 529} 530 531 532#if WXWIN_COMPATIBILITY_2_6 533void wxSizerItem::SetOption( int option ) 534{ 535 SetProportion( option ); 536} 537 538int wxSizerItem::GetOption() const 539{ 540 return GetProportion(); 541} 542#endif // WXWIN_COMPATIBILITY_2_6 543 544 545//--------------------------------------------------------------------------- 546// wxSizer 547//--------------------------------------------------------------------------- 548 549wxSizer::~wxSizer() 550{ 551 WX_CLEAR_LIST(wxSizerItemList, m_children); 552} 553 554wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item ) 555{ 556 m_children.Insert( index, item ); 557 558 if ( item->GetWindow() ) 559 item->GetWindow()->SetContainingSizer( this ); 560 561 if ( item->GetSizer() ) 562 item->GetSizer()->SetContainingWindow( m_containingWindow ); 563 564 return item; 565} 566 567void wxSizer::SetContainingWindow(wxWindow *win) 568{ 569 if ( win == m_containingWindow ) 570 return; 571 572 m_containingWindow = win; 573 574 // set the same window for all nested sizers as well, they also are in the 575 // same window 576 for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 577 node; 578 node = node->GetNext() ) 579 { 580 wxSizerItem *const item = node->GetData(); 581 wxSizer *const sizer = item->GetSizer(); 582 583 if ( sizer ) 584 { 585 sizer->SetContainingWindow(win); 586 } 587 } 588} 589 590#if WXWIN_COMPATIBILITY_2_6 591bool wxSizer::Remove( wxWindow *window ) 592{ 593 return Detach( window ); 594} 595#endif // WXWIN_COMPATIBILITY_2_6 596 597bool wxSizer::Remove( wxSizer *sizer ) 598{ 599 wxASSERT_MSG( sizer, _T("Removing NULL sizer") ); 600 601 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 602 while (node) 603 { 604 wxSizerItem *item = node->GetData(); 605 606 if (item->GetSizer() == sizer) 607 { 608 delete item; 609 m_children.Erase( node ); 610 return true; 611 } 612 613 node = node->GetNext(); 614 } 615 616 return false; 617} 618 619bool wxSizer::Remove( int index ) 620{ 621 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), 622 false, 623 _T("Remove index is out of range") ); 624 625 wxSizerItemList::compatibility_iterator node = m_children.Item( index ); 626 627 wxCHECK_MSG( node, false, _T("Failed to find child node") ); 628 629 wxSizerItem *item = node->GetData(); 630 631 if ( item->IsWindow() ) 632 item->GetWindow()->SetContainingSizer( NULL ); 633 634 delete item; 635 m_children.Erase( node ); 636 return true; 637} 638 639bool wxSizer::Detach( wxSizer *sizer ) 640{ 641 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") ); 642 643 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 644 while (node) 645 { 646 wxSizerItem *item = node->GetData(); 647 648 if (item->GetSizer() == sizer) 649 { 650 item->DetachSizer(); 651 delete item; 652 m_children.Erase( node ); 653 return true; 654 } 655 node = node->GetNext(); 656 } 657 658 return false; 659} 660 661bool wxSizer::Detach( wxWindow *window ) 662{ 663 wxASSERT_MSG( window, _T("Detaching NULL window") ); 664 665 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 666 while (node) 667 { 668 wxSizerItem *item = node->GetData(); 669 670 if (item->GetWindow() == window) 671 { 672 item->GetWindow()->SetContainingSizer( NULL ); 673 delete item; 674 m_children.Erase( node ); 675 return true; 676 } 677 node = node->GetNext(); 678 } 679 680 return false; 681} 682 683bool wxSizer::Detach( int index ) 684{ 685 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), 686 false, 687 _T("Detach index is out of range") ); 688 689 wxSizerItemList::compatibility_iterator node = m_children.Item( index ); 690 691 wxCHECK_MSG( node, false, _T("Failed to find child node") ); 692 693 wxSizerItem *item = node->GetData(); 694 695 if ( item->IsSizer() ) 696 item->DetachSizer(); 697 else if ( item->IsWindow() ) 698 item->GetWindow()->SetContainingSizer( NULL ); 699 700 delete item; 701 m_children.Erase( node ); 702 return true; 703} 704 705bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) 706{ 707 wxASSERT_MSG( oldwin, _T("Replacing NULL window") ); 708 wxASSERT_MSG( newwin, _T("Replacing with NULL window") ); 709 710 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 711 while (node) 712 { 713 wxSizerItem *item = node->GetData(); 714 715 if (item->GetWindow() == oldwin) 716 { 717 item->GetWindow()->SetContainingSizer( NULL ); 718 item->SetWindow(newwin); 719 newwin->SetContainingSizer( this ); 720 return true; 721 } 722 else if (recursive && item->IsSizer()) 723 { 724 if (item->GetSizer()->Replace( oldwin, newwin, true )) 725 return true; 726 } 727 728 node = node->GetNext(); 729 } 730 731 return false; 732} 733 734bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive ) 735{ 736 wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") ); 737 wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") ); 738 739 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 740 while (node) 741 { 742 wxSizerItem *item = node->GetData(); 743 744 if (item->GetSizer() == oldsz) 745 { 746 wxSizer *old = item->GetSizer(); 747 item->SetSizer(newsz); 748 delete old; 749 return true; 750 } 751 else if (recursive && item->IsSizer()) 752 { 753 if (item->GetSizer()->Replace( oldsz, newsz, true )) 754 return true; 755 } 756 757 node = node->GetNext(); 758 } 759 760 return false; 761} 762 763bool wxSizer::Replace( size_t old, wxSizerItem *newitem ) 764{ 765 wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") ); 766 wxASSERT_MSG( newitem, _T("Replacing with NULL item") ); 767 768 wxSizerItemList::compatibility_iterator node = m_children.Item( old ); 769 770 wxCHECK_MSG( node, false, _T("Failed to find child node") ); 771 772 wxSizerItem *item = node->GetData(); 773 node->SetData(newitem); 774 775 if (item->IsWindow() && item->GetWindow()) 776 item->GetWindow()->SetContainingSizer(NULL); 777 778 delete item; 779 780 return true; 781} 782 783void wxSizer::Clear( bool delete_windows ) 784{ 785 // First clear the ContainingSizer pointers 786 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 787 while (node) 788 { 789 wxSizerItem *item = node->GetData(); 790 791 if (item->IsWindow()) 792 item->GetWindow()->SetContainingSizer( NULL ); 793 node = node->GetNext(); 794 } 795 796 // Destroy the windows if needed 797 if (delete_windows) 798 DeleteWindows(); 799 800 // Now empty the list 801 WX_CLEAR_LIST(wxSizerItemList, m_children); 802} 803 804void wxSizer::DeleteWindows() 805{ 806 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 807 while (node) 808 { 809 wxSizerItem *item = node->GetData(); 810 811 item->DeleteWindows(); 812 node = node->GetNext(); 813 } 814} 815 816wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) 817{ 818 // take the min size by default and limit it by max size 819 wxSize size = GetMinWindowSize(window); 820 wxSize sizeMax = GetMaxWindowSize(window); 821 822 wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow); 823 if ( tlw ) 824 { 825 // hack for small screen devices where TLWs are always full screen 826 if ( tlw->IsAlwaysMaximized() ) 827 { 828 size = tlw->GetSize(); 829 } 830 else // normal situation 831 { 832 // limit the window to the size of the display it is on 833 int disp = wxDisplay::GetFromWindow(window); 834 if ( disp == wxNOT_FOUND ) 835 { 836 // or, if we don't know which one it is, of the main one 837 disp = 0; 838 } 839 840 sizeMax = wxDisplay(disp).GetClientArea().GetSize(); 841 } 842 } 843 844 if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x ) 845 size.x = sizeMax.x; 846 if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y ) 847 size.y = sizeMax.y; 848 849 return size; 850} 851 852wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) 853{ 854 wxCHECK_MSG( window, wxDefaultSize, _T("window can't be NULL") ); 855 856 return window->WindowToClientSize(ComputeFittingWindowSize(window)); 857} 858 859wxSize wxSizer::Fit( wxWindow *window ) 860{ 861 wxSize size = ComputeFittingWindowSize(window); 862 window->SetSize(size); 863 return size; 864} 865 866void wxSizer::FitInside( wxWindow *window ) 867{ 868 wxSize size; 869 if (window->IsTopLevel()) 870 size = VirtualFitSize( window ); 871 else 872 size = GetMinClientSize( window ); 873 874 window->SetVirtualSize( size ); 875} 876 877void wxSizer::Layout() 878{ 879 // (re)calculates minimums needed for each item and other preparations 880 // for layout 881 CalcMin(); 882 883 // Applies the layout and repositions/resizes the items 884 RecalcSizes(); 885} 886 887void wxSizer::SetSizeHints( wxWindow *window ) 888{ 889 // Preserve the window's max size hints, but set the 890 // lower bound according to the sizer calculations. 891 892 // This is equivalent to calling Fit(), except that we need to set 893 // the size hints _in between_ the two steps performed by Fit 894 // (1. ComputeFittingWindowSize, 2. SetSize). That's because 895 // otherwise SetSize() could have no effect if there already are 896 // size hints in effect that forbid requested size. 897 const wxSize size = ComputeFittingWindowSize(window); 898 899 window->SetSizeHints( size.x, 900 size.y, 901 window->GetMaxWidth(), 902 window->GetMaxHeight() ); 903 904 window->SetSize(size); 905} 906 907void wxSizer::SetVirtualSizeHints( wxWindow *window ) 908{ 909 // Preserve the window's max size hints, but set the 910 // lower bound according to the sizer calculations. 911 912 FitInside( window ); 913 wxSize size( window->GetVirtualSize() ); 914 window->SetVirtualSizeHints( size.x, 915 size.y, 916 window->GetMaxWidth(), 917 window->GetMaxHeight() ); 918} 919 920wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const 921{ 922 return window->GetMaxSize(); 923} 924 925wxSize wxSizer::GetMinWindowSize( wxWindow *window ) 926{ 927 wxSize minSize( GetMinSize() ); 928 wxSize size( window->GetSize() ); 929 wxSize client_size( window->GetClientSize() ); 930 931 return wxSize( minSize.x+size.x-client_size.x, 932 minSize.y+size.y-client_size.y ); 933} 934 935// TODO on mac we need a function that determines how much free space this 936// min size contains, in order to make sure that we have 20 pixels of free 937// space around the controls 938wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const 939{ 940 wxSize maxSize( window->GetMaxSize() ); 941 942 if ( maxSize != wxDefaultSize ) 943 { 944 wxSize size( window->GetSize() ); 945 wxSize client_size( window->GetClientSize() ); 946 947 return wxSize( maxSize.x + client_size.x - size.x, 948 maxSize.y + client_size.y - size.y ); 949 } 950 else 951 return wxDefaultSize; 952} 953 954wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) ) 955{ 956 return GetMinSize(); // Already returns client size. 957} 958 959wxSize wxSizer::VirtualFitSize( wxWindow *window ) 960{ 961 wxSize size = GetMinClientSize( window ); 962 wxSize sizeMax = GetMaxClientSize( window ); 963 964 // Limit the size if sizeMax != wxDefaultSize 965 966 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord ) 967 size.x = sizeMax.x; 968 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord ) 969 size.y = sizeMax.y; 970 971 return size; 972} 973 974void wxSizer::SetDimension( int x, int y, int width, int height ) 975{ 976 m_position.x = x; 977 m_position.y = y; 978 m_size.x = width; 979 m_size.y = height; 980 Layout(); 981} 982 983wxSize wxSizer::GetMinSize() 984{ 985 wxSize ret( CalcMin() ); 986 if (ret.x < m_minSize.x) ret.x = m_minSize.x; 987 if (ret.y < m_minSize.y) ret.y = m_minSize.y; 988 return ret; 989} 990 991void wxSizer::DoSetMinSize( int width, int height ) 992{ 993 m_minSize.x = width; 994 m_minSize.y = height; 995} 996 997bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height ) 998{ 999 wxASSERT_MSG( window, _T("SetMinSize for NULL window") ); 1000 1001 // Is it our immediate child? 1002 1003 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1004 while (node) 1005 { 1006 wxSizerItem *item = node->GetData(); 1007 1008 if (item->GetWindow() == window) 1009 { 1010 item->SetMinSize( width, height ); 1011 return true; 1012 } 1013 node = node->GetNext(); 1014 } 1015 1016 // No? Search any subsizers we own then 1017 1018 node = m_children.GetFirst(); 1019 while (node) 1020 { 1021 wxSizerItem *item = node->GetData(); 1022 1023 if ( item->GetSizer() && 1024 item->GetSizer()->DoSetItemMinSize( window, width, height ) ) 1025 { 1026 // A child sizer found the requested windw, exit. 1027 return true; 1028 } 1029 node = node->GetNext(); 1030 } 1031 1032 return false; 1033} 1034 1035bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height ) 1036{ 1037 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") ); 1038 1039 // Is it our immediate child? 1040 1041 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1042 while (node) 1043 { 1044 wxSizerItem *item = node->GetData(); 1045 1046 if (item->GetSizer() == sizer) 1047 { 1048 item->GetSizer()->DoSetMinSize( width, height ); 1049 return true; 1050 } 1051 node = node->GetNext(); 1052 } 1053 1054 // No? Search any subsizers we own then 1055 1056 node = m_children.GetFirst(); 1057 while (node) 1058 { 1059 wxSizerItem *item = node->GetData(); 1060 1061 if ( item->GetSizer() && 1062 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) ) 1063 { 1064 // A child found the requested sizer, exit. 1065 return true; 1066 } 1067 node = node->GetNext(); 1068 } 1069 1070 return false; 1071} 1072 1073bool wxSizer::DoSetItemMinSize( size_t index, int width, int height ) 1074{ 1075 wxSizerItemList::compatibility_iterator node = m_children.Item( index ); 1076 1077 wxCHECK_MSG( node, false, _T("Failed to find child node") ); 1078 1079 wxSizerItem *item = node->GetData(); 1080 1081 if (item->GetSizer()) 1082 { 1083 // Sizers contains the minimal size in them, if not calculated ... 1084 item->GetSizer()->DoSetMinSize( width, height ); 1085 } 1086 else 1087 { 1088 // ... but the minimal size of spacers and windows is stored via the item 1089 item->SetMinSize( width, height ); 1090 } 1091 1092 return true; 1093} 1094 1095wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive ) 1096{ 1097 wxASSERT_MSG( window, _T("GetItem for NULL window") ); 1098 1099 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1100 while (node) 1101 { 1102 wxSizerItem *item = node->GetData(); 1103 1104 if (item->GetWindow() == window) 1105 { 1106 return item; 1107 } 1108 else if (recursive && item->IsSizer()) 1109 { 1110 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true ); 1111 if (subitem) 1112 return subitem; 1113 } 1114 1115 node = node->GetNext(); 1116 } 1117 1118 return NULL; 1119} 1120 1121wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive ) 1122{ 1123 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") ); 1124 1125 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1126 while (node) 1127 { 1128 wxSizerItem *item = node->GetData(); 1129 1130 if (item->GetSizer() == sizer) 1131 { 1132 return item; 1133 } 1134 else if (recursive && item->IsSizer()) 1135 { 1136 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true ); 1137 if (subitem) 1138 return subitem; 1139 } 1140 1141 node = node->GetNext(); 1142 } 1143 1144 return NULL; 1145} 1146 1147wxSizerItem* wxSizer::GetItem( size_t index ) 1148{ 1149 wxCHECK_MSG( index < m_children.GetCount(), 1150 NULL, 1151 _T("GetItem index is out of range") ); 1152 1153 return m_children.Item( index )->GetData(); 1154} 1155 1156bool wxSizer::Show( wxWindow *window, bool show, bool recursive ) 1157{ 1158 wxSizerItem *item = GetItem( window, recursive ); 1159 1160 if ( item ) 1161 { 1162 item->Show( show ); 1163 return true; 1164 } 1165 1166 return false; 1167} 1168 1169bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive ) 1170{ 1171 wxSizerItem *item = GetItem( sizer, recursive ); 1172 1173 if ( item ) 1174 { 1175 item->Show( show ); 1176 return true; 1177 } 1178 1179 return false; 1180} 1181 1182bool wxSizer::Show( size_t index, bool show) 1183{ 1184 wxSizerItem *item = GetItem( index ); 1185 1186 if ( item ) 1187 { 1188 item->Show( show ); 1189 return true; 1190 } 1191 1192 return false; 1193} 1194 1195void wxSizer::ShowItems( bool show ) 1196{ 1197 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1198 while (node) 1199 { 1200 node->GetData()->Show( show ); 1201 node = node->GetNext(); 1202 } 1203} 1204 1205bool wxSizer::IsShown( wxWindow *window ) const 1206{ 1207 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1208 while (node) 1209 { 1210 wxSizerItem *item = node->GetData(); 1211 1212 if (item->GetWindow() == window) 1213 { 1214 return item->IsShown(); 1215 } 1216 node = node->GetNext(); 1217 } 1218 1219 wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 1220 1221 return false; 1222} 1223 1224bool wxSizer::IsShown( wxSizer *sizer ) const 1225{ 1226 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1227 while (node) 1228 { 1229 wxSizerItem *item = node->GetData(); 1230 1231 if (item->GetSizer() == sizer) 1232 { 1233 return item->IsShown(); 1234 } 1235 node = node->GetNext(); 1236 } 1237 1238 wxFAIL_MSG( _T("IsShown failed to find sizer item") ); 1239 1240 return false; 1241} 1242 1243bool wxSizer::IsShown( size_t index ) const 1244{ 1245 wxCHECK_MSG( index < m_children.GetCount(), 1246 false, 1247 _T("IsShown index is out of range") ); 1248 1249 return m_children.Item( index )->GetData()->IsShown(); 1250} 1251 1252 1253//--------------------------------------------------------------------------- 1254// wxGridSizer 1255//--------------------------------------------------------------------------- 1256 1257wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap ) 1258 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows ) 1259 , m_cols( cols ) 1260 , m_vgap( vgap ) 1261 , m_hgap( hgap ) 1262{ 1263} 1264 1265wxGridSizer::wxGridSizer( int cols, int vgap, int hgap ) 1266 : m_rows( cols == 0 ? 1 : 0 ) 1267 , m_cols( cols ) 1268 , m_vgap( vgap ) 1269 , m_hgap( hgap ) 1270{ 1271} 1272 1273int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const 1274{ 1275 int nitems = m_children.GetCount(); 1276 if ( nitems) 1277 { 1278 if ( m_cols ) 1279 { 1280 ncols = m_cols; 1281 nrows = (nitems + m_cols - 1) / m_cols; 1282 } 1283 else if ( m_rows ) 1284 { 1285 ncols = (nitems + m_rows - 1) / m_rows; 1286 nrows = m_rows; 1287 } 1288 else // 0 columns, 0 rows? 1289 { 1290 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); 1291 1292 nrows = ncols = 0; 1293 } 1294 } 1295 1296 return nitems; 1297} 1298 1299void wxGridSizer::RecalcSizes() 1300{ 1301 int nitems, nrows, ncols; 1302 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) 1303 return; 1304 1305 wxSize sz( GetSize() ); 1306 wxPoint pt( GetPosition() ); 1307 1308 int w = (sz.x - (ncols - 1) * m_hgap) / ncols; 1309 int h = (sz.y - (nrows - 1) * m_vgap) / nrows; 1310 1311 int x = pt.x; 1312 for (int c = 0; c < ncols; c++) 1313 { 1314 int y = pt.y; 1315 for (int r = 0; r < nrows; r++) 1316 { 1317 int i = r * ncols + c; 1318 if (i < nitems) 1319 { 1320 wxSizerItemList::compatibility_iterator node = m_children.Item( i ); 1321 1322 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") ); 1323 1324 SetItemBounds( node->GetData(), x, y, w, h); 1325 } 1326 y = y + h + m_vgap; 1327 } 1328 x = x + w + m_hgap; 1329 } 1330} 1331 1332wxSize wxGridSizer::CalcMin() 1333{ 1334 int nrows, ncols; 1335 if ( CalcRowsCols(nrows, ncols) == 0 ) 1336 return wxSize(); 1337 1338 // Find the max width and height for any component 1339 int w = 0; 1340 int h = 0; 1341 1342 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1343 while (node) 1344 { 1345 wxSizerItem *item = node->GetData(); 1346 wxSize sz( item->CalcMin() ); 1347 1348 w = wxMax( w, sz.x ); 1349 h = wxMax( h, sz.y ); 1350 1351 node = node->GetNext(); 1352 } 1353 1354 return wxSize( ncols * w + (ncols-1) * m_hgap, 1355 nrows * h + (nrows-1) * m_vgap ); 1356} 1357 1358void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h ) 1359{ 1360 wxPoint pt( x,y ); 1361 wxSize sz( item->GetMinSizeWithBorder() ); 1362 int flag = item->GetFlag(); 1363 1364 if ((flag & wxEXPAND) || (flag & wxSHAPED)) 1365 { 1366 sz = wxSize(w, h); 1367 } 1368 else 1369 { 1370 if (flag & wxALIGN_CENTER_HORIZONTAL) 1371 { 1372 pt.x = x + (w - sz.x) / 2; 1373 } 1374 else if (flag & wxALIGN_RIGHT) 1375 { 1376 pt.x = x + (w - sz.x); 1377 } 1378 1379 if (flag & wxALIGN_CENTER_VERTICAL) 1380 { 1381 pt.y = y + (h - sz.y) / 2; 1382 } 1383 else if (flag & wxALIGN_BOTTOM) 1384 { 1385 pt.y = y + (h - sz.y); 1386 } 1387 } 1388 1389 item->SetDimension(pt, sz); 1390} 1391 1392//--------------------------------------------------------------------------- 1393// wxFlexGridSizer 1394//--------------------------------------------------------------------------- 1395 1396wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap ) 1397 : wxGridSizer( rows, cols, vgap, hgap ), 1398 m_flexDirection(wxBOTH), 1399 m_growMode(wxFLEX_GROWMODE_SPECIFIED) 1400{ 1401} 1402 1403wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap ) 1404 : wxGridSizer( cols, vgap, hgap ), 1405 m_flexDirection(wxBOTH), 1406 m_growMode(wxFLEX_GROWMODE_SPECIFIED) 1407{ 1408} 1409 1410wxFlexGridSizer::~wxFlexGridSizer() 1411{ 1412} 1413 1414void wxFlexGridSizer::RecalcSizes() 1415{ 1416 int nitems, nrows, ncols; 1417 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) 1418 return; 1419 1420 wxPoint pt( GetPosition() ); 1421 wxSize sz( GetSize() ); 1422 1423 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols); 1424 1425 sz = wxSize( pt.x + sz.x, pt.y + sz.y ); 1426 1427 int x = pt.x; 1428 for (int c = 0; c < ncols; c++) 1429 { 1430 int y = pt.y; 1431 for (int r = 0; r < nrows; r++) 1432 { 1433 int i = r * ncols + c; 1434 if (i < nitems) 1435 { 1436 wxSizerItemList::compatibility_iterator node = m_children.Item( i ); 1437 1438 wxASSERT_MSG( node, _T("Failed to find node") ); 1439 1440 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) ); 1441 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) ); 1442 1443 SetItemBounds( node->GetData(), x, y, w, h); 1444 } 1445 if (m_rowHeights[r] != -1) 1446 y = y + m_rowHeights[r] + m_vgap; 1447 } 1448 if (m_colWidths[c] != -1) 1449 x = x + m_colWidths[c] + m_hgap; 1450 } 1451} 1452 1453wxSize wxFlexGridSizer::CalcMin() 1454{ 1455 int nrows, 1456 ncols; 1457 size_t i, s; 1458 1459 // Number of rows/columns can change as items are added or removed. 1460 if ( !CalcRowsCols(nrows, ncols) ) 1461 return wxSize(); 1462 1463 m_rowHeights.SetCount(nrows); 1464 m_colWidths.SetCount(ncols); 1465 1466 // We have to recalcuate the sizes in case the item minimum size has 1467 // changed since the previous layout, or the item has been hidden using 1468 // wxSizer::Show(). If all the items in a row/column are hidden, the final 1469 // dimension of the row/column will be -1, indicating that the column 1470 // itself is hidden. 1471 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i ) 1472 m_rowHeights[ i ] = -1; 1473 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i ) 1474 m_colWidths[ i ] = -1; 1475 1476 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1477 1478 i = 0; 1479 while (node) 1480 { 1481 wxSizerItem *item = node->GetData(); 1482 if ( item->ShouldAccountFor() ) 1483 { 1484 wxSize sz( item->CalcMin() ); 1485 int row = i / ncols; 1486 int col = i % ncols; 1487 1488 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] ); 1489 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] ); 1490 } 1491 1492 node = node->GetNext(); 1493 i++; 1494 } 1495 1496 AdjustForFlexDirection(); 1497 1498 // Sum total minimum size, including gaps between rows/columns. 1499 // -1 is used as a magic number meaning empty column. 1500 int width = 0; 1501 for (int col = 0; col < ncols; col++) 1502 if ( m_colWidths[ col ] != -1 ) 1503 width += m_colWidths[ col ] + m_hgap; 1504 if (width > 0) 1505 width -= m_hgap; 1506 1507 int height = 0; 1508 for (int row = 0; row < nrows; row++) 1509 if ( m_rowHeights[ row ] != -1 ) 1510 height += m_rowHeights[ row ] + m_vgap; 1511 if (height > 0) 1512 height -= m_vgap; 1513 1514 m_calculatedMinSize = wxSize( width, height ); 1515 return m_calculatedMinSize; 1516} 1517 1518void wxFlexGridSizer::AdjustForFlexDirection() 1519{ 1520 // the logic in CalcMin works when we resize flexibly in both directions 1521 // but maybe this is not the case 1522 if ( m_flexDirection != wxBOTH ) 1523 { 1524 // select the array corresponding to the direction in which we do *not* 1525 // resize flexibly 1526 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths 1527 : m_rowHeights; 1528 1529 const size_t count = array.GetCount(); 1530 1531 // find the largest value in this array 1532 size_t n; 1533 int largest = 0; 1534 1535 for ( n = 0; n < count; ++n ) 1536 { 1537 if ( array[n] > largest ) 1538 largest = array[n]; 1539 } 1540 1541 // and now fill it with the largest value 1542 for ( n = 0; n < count; ++n ) 1543 { 1544 // don't touch hidden rows 1545 if ( array[n] != -1 ) 1546 array[n] = largest; 1547 } 1548 } 1549} 1550 1551 1552void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz, 1553 int nrows, int ncols) 1554{ 1555 // what to do with the rows? by default, resize them proportionally 1556 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) 1557 { 1558 int sum_proportions = 0; 1559 int growable_space = 0; 1560 int num = 0; 1561 size_t idx; 1562 for (idx = 0; idx < m_growableRows.GetCount(); idx++) 1563 { 1564 // Since the number of rows/columns can change as items are 1565 // inserted/deleted, we need to verify at runtime that the 1566 // requested growable rows/columns are still valid. 1567 if (m_growableRows[idx] >= nrows) 1568 continue; 1569 1570 // If all items in a row/column are hidden, that row/column will 1571 // have a dimension of -1. This causes the row/column to be 1572 // hidden completely. 1573 if (m_rowHeights[ m_growableRows[idx] ] == -1) 1574 continue; 1575 sum_proportions += m_growableRowsProportions[idx]; 1576 growable_space += m_rowHeights[ m_growableRows[idx] ]; 1577 num++; 1578 } 1579 1580 if (num > 0) 1581 { 1582 for (idx = 0; idx < m_growableRows.GetCount(); idx++) 1583 { 1584 if (m_growableRows[idx] >= nrows ) 1585 continue; 1586 if (m_rowHeights[ m_growableRows[idx] ] != -1) 1587 { 1588 int delta = (sz.y - minsz.y); 1589 if (sum_proportions == 0) 1590 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ]; 1591 else 1592 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions; 1593 m_rowHeights[ m_growableRows[idx] ] = delta; 1594 } 1595 } 1596 } 1597 } 1598 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) ) 1599 { 1600 // rounding problem? 1601 for ( int row = 0; row < nrows; ++row ) 1602 m_rowHeights[ row ] = sz.y / nrows; 1603 } 1604 1605 // the same logic as above but for the columns 1606 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) 1607 { 1608 int sum_proportions = 0; 1609 int growable_space = 0; 1610 int num = 0; 1611 size_t idx; 1612 for (idx = 0; idx < m_growableCols.GetCount(); idx++) 1613 { 1614 // Since the number of rows/columns can change as items are 1615 // inserted/deleted, we need to verify at runtime that the 1616 // requested growable rows/columns are still valid. 1617 if (m_growableCols[idx] >= ncols) 1618 continue; 1619 1620 // If all items in a row/column are hidden, that row/column will 1621 // have a dimension of -1. This causes the column to be hidden 1622 // completely. 1623 if (m_colWidths[ m_growableCols[idx] ] == -1) 1624 continue; 1625 sum_proportions += m_growableColsProportions[idx]; 1626 growable_space += m_colWidths[ m_growableCols[idx] ]; 1627 num++; 1628 } 1629 1630 if (num > 0) 1631 { 1632 for (idx = 0; idx < m_growableCols.GetCount(); idx++) 1633 { 1634 if (m_growableCols[idx] >= ncols ) 1635 continue; 1636 if (m_colWidths[ m_growableCols[idx] ] != -1) 1637 { 1638 int delta = (sz.x - minsz.x); 1639 if (sum_proportions == 0) 1640 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ]; 1641 else 1642 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions; 1643 m_colWidths[ m_growableCols[idx] ] = delta; 1644 } 1645 } 1646 } 1647 } 1648 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) ) 1649 { 1650 for ( int col=0; col < ncols; ++col ) 1651 m_colWidths[ col ] = sz.x / ncols; 1652 } 1653} 1654 1655 1656void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion ) 1657{ 1658 m_growableRows.Add( idx ); 1659 m_growableRowsProportions.Add( proportion ); 1660} 1661 1662void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion ) 1663{ 1664 m_growableCols.Add( idx ); 1665 m_growableColsProportions.Add( proportion ); 1666} 1667 1668// helper function for RemoveGrowableCol/Row() 1669static void 1670DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions) 1671{ 1672 const size_t count = items.size(); 1673 for ( size_t n = 0; n < count; n++ ) 1674 { 1675 if ( (size_t)items[n] == idx ) 1676 { 1677 items.RemoveAt(n); 1678 proportions.RemoveAt(n); 1679 return; 1680 } 1681 } 1682 1683 wxFAIL_MSG( _T("column/row is already not growable") ); 1684} 1685 1686void wxFlexGridSizer::RemoveGrowableCol( size_t idx ) 1687{ 1688 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions); 1689} 1690 1691void wxFlexGridSizer::RemoveGrowableRow( size_t idx ) 1692{ 1693 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions); 1694} 1695 1696//--------------------------------------------------------------------------- 1697// wxBoxSizer 1698//--------------------------------------------------------------------------- 1699 1700wxBoxSizer::wxBoxSizer( int orient ) 1701 : m_orient( orient ) 1702{ 1703} 1704 1705void wxBoxSizer::RecalcSizes() 1706{ 1707 if (m_children.GetCount() == 0) 1708 return; 1709 1710 int delta = 0; 1711 if (m_stretchable) 1712 { 1713 if (m_orient == wxHORIZONTAL) 1714 delta = m_size.x - m_fixedWidth; 1715 else 1716 delta = m_size.y - m_fixedHeight; 1717 } 1718 1719 wxPoint pt( m_position ); 1720 1721 int stretchable = m_stretchable; 1722 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1723 while (node) 1724 { 1725 wxSizerItem *item = node->GetData(); 1726 1727 if (item->ShouldAccountFor()) 1728 { 1729 wxSize size( item->GetMinSizeWithBorder() ); 1730 1731 if (m_orient == wxVERTICAL) 1732 { 1733 wxCoord height = size.y; 1734 if (item->GetProportion()) 1735 { 1736 // Because of at least one visible item has non-zero 1737 // proportion then m_stretchable is not zero 1738 height = (delta * item->GetProportion()) / stretchable; 1739 delta -= height; 1740 stretchable -= item->GetProportion(); 1741 } 1742 1743 wxPoint child_pos( pt ); 1744 wxSize child_size( size.x, height ); 1745 1746 if (item->GetFlag() & (wxEXPAND | wxSHAPED)) 1747 child_size.x = m_size.x; 1748 else if (item->GetFlag() & wxALIGN_RIGHT) 1749 child_pos.x += m_size.x - size.x; 1750 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL)) 1751 // XXX wxCENTER is added for backward compatibility; 1752 // wxALIGN_CENTER should be used in new code 1753 child_pos.x += (m_size.x - size.x) / 2; 1754 1755 item->SetDimension( child_pos, child_size ); 1756 1757 pt.y += height; 1758 } 1759 else 1760 { 1761 wxCoord width = size.x; 1762 if (item->GetProportion()) 1763 { 1764 // Because of at least one visible item has non-zero 1765 // proportion then m_stretchable is not zero 1766 width = (delta * item->GetProportion()) / stretchable; 1767 delta -= width; 1768 stretchable -= item->GetProportion(); 1769 } 1770 1771 wxPoint child_pos( pt ); 1772 wxSize child_size( width, size.y ); 1773 1774 if (item->GetFlag() & (wxEXPAND | wxSHAPED)) 1775 child_size.y = m_size.y; 1776 else if (item->GetFlag() & wxALIGN_BOTTOM) 1777 child_pos.y += m_size.y - size.y; 1778 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL)) 1779 // XXX wxCENTER is added for backward compatibility; 1780 // wxALIGN_CENTER should be used in new code 1781 child_pos.y += (m_size.y - size.y) / 2; 1782 1783 if ( m_containingWindow ) 1784 { 1785 child_pos.x = m_containingWindow->AdjustForLayoutDirection 1786 ( 1787 child_pos.x, 1788 width, 1789 m_size.x 1790 ); 1791 } 1792 1793 item->SetDimension( child_pos, child_size ); 1794 1795 pt.x += width; 1796 } 1797 } 1798 1799 node = node->GetNext(); 1800 } 1801} 1802 1803wxSize wxBoxSizer::CalcMin() 1804{ 1805 if (m_children.GetCount() == 0) 1806 return wxSize(); 1807 1808 m_stretchable = 0; 1809 m_minWidth = 0; 1810 m_minHeight = 0; 1811 m_fixedWidth = 0; 1812 m_fixedHeight = 0; 1813 1814 // precalc item minsizes and count proportions 1815 wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); 1816 while (node) 1817 { 1818 wxSizerItem *item = node->GetData(); 1819 1820 if ( item->ShouldAccountFor() ) 1821 { 1822 item->CalcMin(); // result is stored in the item 1823 1824 m_stretchable += item->GetProportion(); 1825 } 1826 1827 node = node->GetNext(); 1828 } 1829 1830 // Total minimum size (width or height) of sizer 1831 int maxMinSize = 0; 1832 1833 node = m_children.GetFirst(); 1834 while (node) 1835 { 1836 wxSizerItem *item = node->GetData(); 1837 1838 if (item->ShouldAccountFor() && item->GetProportion() != 0) 1839 { 1840 int stretch = item->GetProportion(); 1841 wxSize size( item->GetMinSizeWithBorder() ); 1842 int minSize; 1843 1844 // Integer division rounded up is (a + b - 1) / b 1845 // Round up needed in order to guarantee that all 1846 // all items will have size not less then their min size 1847 if (m_orient == wxHORIZONTAL) 1848 minSize = ( size.x*m_stretchable + stretch - 1)/stretch; 1849 else 1850 minSize = ( size.y*m_stretchable + stretch - 1)/stretch; 1851 1852 if (minSize > maxMinSize) 1853 maxMinSize = minSize; 1854 } 1855 node = node->GetNext(); 1856 } 1857 1858 // Calculate overall minimum size 1859 node = m_children.GetFirst(); 1860 while (node) 1861 { 1862 wxSizerItem *item = node->GetData(); 1863 1864 if (item->ShouldAccountFor()) 1865 { 1866 wxSize size( item->GetMinSizeWithBorder() ); 1867 if (item->GetProportion() != 0) 1868 { 1869 if (m_orient == wxHORIZONTAL) 1870 size.x = (maxMinSize*item->GetProportion())/m_stretchable; 1871 else 1872 size.y = (maxMinSize*item->GetProportion())/m_stretchable; 1873 } 1874 else 1875 { 1876 if (m_orient == wxVERTICAL) 1877 { 1878 m_fixedHeight += size.y; 1879 m_fixedWidth = wxMax( m_fixedWidth, size.x ); 1880 } 1881 else 1882 { 1883 m_fixedWidth += size.x; 1884 m_fixedHeight = wxMax( m_fixedHeight, size.y ); 1885 } 1886 } 1887 1888 if (m_orient == wxHORIZONTAL) 1889 { 1890 m_minWidth += size.x; 1891 m_minHeight = wxMax( m_minHeight, size.y ); 1892 } 1893 else 1894 { 1895 m_minHeight += size.y; 1896 m_minWidth = wxMax( m_minWidth, size.x ); 1897 } 1898 } 1899 node = node->GetNext(); 1900 } 1901 1902 return wxSize( m_minWidth, m_minHeight ); 1903} 1904 1905//--------------------------------------------------------------------------- 1906// wxStaticBoxSizer 1907//--------------------------------------------------------------------------- 1908 1909#if wxUSE_STATBOX 1910 1911wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient ) 1912 : wxBoxSizer( orient ), 1913 m_staticBox( box ) 1914{ 1915 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") ); 1916 1917 // do this so that our Detach() is called if the static box is destroyed 1918 // before we are 1919 m_staticBox->SetContainingSizer(this); 1920} 1921 1922wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s) 1923 : wxBoxSizer(orient), 1924 m_staticBox(new wxStaticBox(win, wxID_ANY, s)) 1925{ 1926 // same as above 1927 m_staticBox->SetContainingSizer(this); 1928} 1929 1930wxStaticBoxSizer::~wxStaticBoxSizer() 1931{ 1932 delete m_staticBox; 1933} 1934 1935static void GetStaticBoxBorders( wxStaticBox *box, 1936 int *borderTop, 1937 int *borderOther) 1938{ 1939 // this has to be done platform by platform as there is no way to 1940 // guess the thickness of a wxStaticBox border 1941 box->GetBordersForSizer(borderTop, borderOther); 1942} 1943 1944void wxStaticBoxSizer::RecalcSizes() 1945{ 1946 int top_border, other_border; 1947 GetStaticBoxBorders(m_staticBox, &top_border, &other_border); 1948 1949 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); 1950 1951 wxPoint old_pos( m_position ); 1952 m_position.x += other_border; 1953 m_position.y += top_border; 1954 wxSize old_size( m_size ); 1955 m_size.x -= 2*other_border; 1956 m_size.y -= top_border + other_border; 1957 1958 wxBoxSizer::RecalcSizes(); 1959 1960 m_position = old_pos; 1961 m_size = old_size; 1962} 1963 1964wxSize wxStaticBoxSizer::CalcMin() 1965{ 1966 int top_border, other_border; 1967 GetStaticBoxBorders(m_staticBox, &top_border, &other_border); 1968 1969 wxSize ret( wxBoxSizer::CalcMin() ); 1970 ret.x += 2*other_border; 1971 ret.y += other_border + top_border; 1972 1973 return ret; 1974} 1975 1976void wxStaticBoxSizer::ShowItems( bool show ) 1977{ 1978 m_staticBox->Show( show ); 1979 wxBoxSizer::ShowItems( show ); 1980} 1981 1982bool wxStaticBoxSizer::Detach( wxWindow *window ) 1983{ 1984 // avoid deleting m_staticBox in our dtor if it's being detached from the 1985 // sizer (which can happen because it's being already destroyed for 1986 // example) 1987 if ( window == m_staticBox ) 1988 { 1989 m_staticBox = NULL; 1990 return true; 1991 } 1992 1993 return wxSizer::Detach( window ); 1994} 1995 1996#endif // wxUSE_STATBOX 1997 1998#if wxUSE_BUTTON 1999 2000wxStdDialogButtonSizer::wxStdDialogButtonSizer() 2001 : wxBoxSizer(wxHORIZONTAL) 2002{ 2003 // Vertical buttons with lots of space on either side 2004 // looks rubbish on WinCE, so let's not do this for now. 2005 // If we are going to use vertical buttons, we should 2006 // put the sizer to the right of other controls in the dialog, 2007 // and that's beyond the scope of this sizer. 2008#ifndef __WXWINCE__ 2009 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); 2010 // If we have a PDA screen, put yes/no button over 2011 // all other buttons, otherwise on the left side. 2012 if (is_pda) 2013 m_orient = wxVERTICAL; 2014#endif 2015 2016 m_buttonAffirmative = NULL; 2017 m_buttonApply = NULL; 2018 m_buttonNegative = NULL; 2019 m_buttonCancel = NULL; 2020 m_buttonHelp = NULL; 2021} 2022 2023void wxStdDialogButtonSizer::AddButton(wxButton *mybutton) 2024{ 2025 switch (mybutton->GetId()) 2026 { 2027 case wxID_OK: 2028 case wxID_YES: 2029 case wxID_SAVE: 2030 m_buttonAffirmative = mybutton; 2031 break; 2032 case wxID_APPLY: 2033 m_buttonApply = mybutton; 2034 break; 2035 case wxID_NO: 2036 m_buttonNegative = mybutton; 2037 break; 2038 case wxID_CANCEL: 2039 m_buttonCancel = mybutton; 2040 break; 2041 case wxID_HELP: 2042 case wxID_CONTEXT_HELP: 2043 m_buttonHelp = mybutton; 2044 break; 2045 default: 2046 break; 2047 } 2048} 2049 2050void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button ) 2051{ 2052 m_buttonAffirmative = button; 2053} 2054 2055void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button ) 2056{ 2057 m_buttonNegative = button; 2058} 2059 2060void wxStdDialogButtonSizer::SetCancelButton( wxButton *button ) 2061{ 2062 m_buttonCancel = button; 2063} 2064 2065void wxStdDialogButtonSizer::Realize() 2066{ 2067#ifdef __WXMAC__ 2068 Add(0, 0, 0, wxLEFT, 6); 2069 if (m_buttonHelp) 2070 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); 2071 2072 if (m_buttonNegative){ 2073 // HIG POLICE BULLETIN - destructive buttons need extra padding 2074 // 24 pixels on either side 2075 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12); 2076 } 2077 2078 // extra whitespace between help/negative and cancel/ok buttons 2079 Add(0, 0, 1, wxEXPAND, 0); 2080 2081 if (m_buttonCancel){ 2082 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); 2083 // Cancel or help should be default 2084 // m_buttonCancel->SetDefaultButton(); 2085 } 2086 2087 // Ugh, Mac doesn't really have apply dialogs, so I'll just 2088 // figure the best place is between Cancel and OK 2089 if (m_buttonApply) 2090 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); 2091 2092 if (m_buttonAffirmative){ 2093 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); 2094 2095 if (m_buttonAffirmative->GetId() == wxID_SAVE){ 2096 // these buttons have set labels under Mac so we should use them 2097 m_buttonAffirmative->SetLabel(_("Save")); 2098 if (m_buttonNegative) 2099 m_buttonNegative->SetLabel(_("Don't Save")); 2100 } 2101 } 2102 2103 // Extra space around and at the right 2104 Add(12, 24); 2105#elif defined(__WXGTK20__) 2106 Add(0, 0, 0, wxLEFT, 9); 2107 if (m_buttonHelp) 2108 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); 2109 2110 // extra whitespace between help and cancel/ok buttons 2111 Add(0, 0, 1, wxEXPAND, 0); 2112 2113 if (m_buttonNegative){ 2114 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); 2115 } 2116 2117 if (m_buttonCancel){ 2118 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); 2119 // Cancel or help should be default 2120 // m_buttonCancel->SetDefaultButton(); 2121 } 2122 2123 if (m_buttonApply) 2124 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); 2125 2126 if (m_buttonAffirmative) 2127 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); 2128#elif defined(__WXMSW__) 2129 // Windows 2130 2131 // right-justify buttons 2132 Add(0, 0, 1, wxEXPAND, 0); 2133 2134 if (m_buttonAffirmative){ 2135 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x); 2136 } 2137 2138 if (m_buttonNegative){ 2139 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x); 2140 } 2141 2142 if (m_buttonCancel){ 2143 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x); 2144 } 2145 if (m_buttonApply) 2146 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x); 2147 2148 if (m_buttonHelp) 2149 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x); 2150#else 2151 // GTK+1 and any other platform 2152 2153 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog 2154 if (m_buttonHelp) 2155 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x); 2156 2157 // extra whitespace between help and cancel/ok buttons 2158 Add(0, 0, 1, wxEXPAND, 0); 2159 2160 if (m_buttonApply) 2161 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x); 2162 2163 if (m_buttonAffirmative){ 2164 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x); 2165 } 2166 2167 if (m_buttonNegative){ 2168 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x); 2169 } 2170 2171 if (m_buttonCancel){ 2172 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x); 2173 // Cancel or help should be default 2174 // m_buttonCancel->SetDefaultButton(); 2175 } 2176 2177#endif 2178} 2179 2180#endif // wxUSE_BUTTON 2181 2182#if WXWIN_COMPATIBILITY_2_4 2183 2184// ---------------------------------------------------------------------------- 2185// wxNotebookSizer 2186// ---------------------------------------------------------------------------- 2187 2188#if wxUSE_BOOKCTRL 2189IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer) 2190#if wxUSE_NOTEBOOK 2191IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer) 2192#endif // wxUSE_NOTEBOOK 2193#endif // wxUSE_BOOKCTRL 2194 2195#if wxUSE_BOOKCTRL 2196 2197#if WXWIN_COMPATIBILITY_2_6 2198 2199wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl) 2200 : m_bookctrl(bookctrl) 2201{ 2202 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") ); 2203} 2204 2205#endif // WXWIN_COMPATIBILITY_2_6 2206 2207void wxBookCtrlSizer::RecalcSizes() 2208{ 2209 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); 2210} 2211 2212wxSize wxBookCtrlSizer::CalcMin() 2213{ 2214 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0)); 2215 2216 sizeBorder.x += 5; 2217 sizeBorder.y += 5; 2218 2219 if ( m_bookctrl->GetPageCount() == 0 ) 2220 { 2221 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10); 2222 } 2223 2224 int maxX = 0; 2225 int maxY = 0; 2226 2227 wxWindowList::compatibility_iterator 2228 node = m_bookctrl->GetChildren().GetFirst(); 2229 while (node) 2230 { 2231 wxWindow *item = node->GetData(); 2232 wxSizer *itemsizer = item->GetSizer(); 2233 2234 if (itemsizer) 2235 { 2236 wxSize subsize( itemsizer->CalcMin() ); 2237 2238 if (subsize.x > maxX) 2239 maxX = subsize.x; 2240 if (subsize.y > maxY) 2241 maxY = subsize.y; 2242 } 2243 2244 node = node->GetNext(); 2245 } 2246 2247 return wxSize( maxX, maxY ) + sizeBorder; 2248} 2249 2250#if wxUSE_NOTEBOOK 2251 2252#if WXWIN_COMPATIBILITY_2_6 2253 2254wxNotebookSizer::wxNotebookSizer(wxNotebook *nb) 2255{ 2256 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") ); 2257 m_bookctrl = nb; 2258} 2259 2260#endif // WXWIN_COMPATIBILITY_2_6 2261 2262#endif // wxUSE_NOTEBOOOK 2263#endif // wxUSE_BOOKCTRL 2264 2265#endif // WXWIN_COMPATIBILITY_2_4 2266