1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxGridBagSizer:  A sizer that can lay out items in a grid, 
   4 //              with items at specified cells, and with the option of row 
   5 //              and/or column spanning 
   8 // Created:     03-Nov-2003 
  10 // Copyright:   (c) Robin Dunn 
  11 // Licence:     wxWindows licence 
  12 ///////////////////////////////////////////////////////////////////////////// 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  21 #include "wx/gbsizer.h" 
  23 //--------------------------------------------------------------------------- 
  25 IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem
, wxSizerItem
) 
  26 IMPLEMENT_CLASS(wxGridBagSizer
, wxFlexGridSizer
) 
  28 const wxGBSpan wxDefaultSpan
; 
  30 //--------------------------------------------------------------------------- 
  32 //--------------------------------------------------------------------------- 
  34 wxGBSizerItem::wxGBSizerItem( int width
, 
  36                               const wxGBPosition
& pos
, 
  41     : wxSizerItem(width
, height
, 0, flag
, border
, userData
), 
  49 wxGBSizerItem::wxGBSizerItem( wxWindow 
*window
, 
  50                               const wxGBPosition
& pos
, 
  55     : wxSizerItem(window
, 0, flag
, border
, userData
), 
  63 wxGBSizerItem::wxGBSizerItem( wxSizer 
*sizer
, 
  64                               const wxGBPosition
& pos
, 
  69     : wxSizerItem(sizer
, 0, flag
, border
, userData
), 
  76 wxGBSizerItem::wxGBSizerItem() 
  84 //--------------------------------------------------------------------------- 
  87 void wxGBSizerItem::GetPos(int& row
, int& col
) const 
  93 void wxGBSizerItem::GetSpan(int& rowspan
, int& colspan
) const 
  95     rowspan 
= m_span
.GetRowspan(); 
  96     colspan 
= m_span
.GetColspan(); 
 100 bool wxGBSizerItem::SetPos( const wxGBPosition
& pos 
) 
 104         wxCHECK_MSG( !m_gbsizer
->CheckForIntersection(pos
, m_span
, this), false, 
 105                  wxT("An item is already at that position") ); 
 111 bool wxGBSizerItem::SetSpan( const wxGBSpan
& span 
) 
 115         wxCHECK_MSG( !m_gbsizer
->CheckForIntersection(m_pos
, span
, this), false, 
 116                  wxT("An item is already at that position") ); 
 123 inline bool InRange(int val
, int min
, int max
) 
 125     return (val 
>= min 
&& val 
<= max
); 
 128 bool wxGBSizerItem::Intersects(const wxGBSizerItem
& other
) 
 130     return Intersects(other
.GetPos(), other
.GetSpan()); 
 133 bool wxGBSizerItem::Intersects(const wxGBPosition
& pos
, const wxGBSpan
& span
) 
 136     int row
, col
, endrow
, endcol
; 
 137     int otherrow
, othercol
, otherendrow
, otherendcol
; 
 140     GetEndPos(endrow
, endcol
); 
 142     otherrow 
= pos
.GetRow(); 
 143     othercol 
= pos
.GetCol(); 
 144     otherendrow 
= otherrow 
+ span
.GetRowspan() - 1; 
 145     otherendcol 
= othercol 
+ span
.GetColspan() - 1; 
 147     // is the other item's start or end in the range of this one? 
 148     if (( InRange(otherrow
, row
, endrow
) && InRange(othercol
, col
, endcol
) ) || 
 149         ( InRange(otherendrow
, row
, endrow
) && InRange(otherendcol
, col
, endcol
) )) 
 152     // is this item's start or end in the range of the other one? 
 153     if (( InRange(row
, otherrow
, otherendrow
) && InRange(col
, othercol
, otherendcol
) ) || 
 154         ( InRange(endrow
, otherrow
, otherendrow
) && InRange(endcol
, othercol
, otherendcol
) )) 
 161 void wxGBSizerItem::GetEndPos(int& row
, int& col
) 
 163     row 
= m_pos
.GetRow() + m_span
.GetRowspan() - 1; 
 164     col 
= m_pos
.GetCol() + m_span
.GetColspan() - 1; 
 168 //--------------------------------------------------------------------------- 
 170 //--------------------------------------------------------------------------- 
 172 wxGridBagSizer::wxGridBagSizer(int vgap
, int hgap 
) 
 173     : wxFlexGridSizer(1, vgap
, hgap
), 
 174       m_emptyCellSize(10,20) 
 180 wxSizerItem
* wxGridBagSizer::Add( wxWindow 
*window
, 
 181                                   const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 182                                   int flag
, int border
,  wxObject
* userData 
) 
 184     wxGBSizerItem
* item 
= new wxGBSizerItem(window
, pos
, span
, flag
, border
, userData
); 
 190         return (wxSizerItem
*)NULL
; 
 194 wxSizerItem
* wxGridBagSizer::Add( wxSizer 
*sizer
, 
 195                           const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 196                           int flag
, int border
,  wxObject
* userData 
) 
 198     wxGBSizerItem
* item 
= new wxGBSizerItem(sizer
, pos
, span
, flag
, border
, userData
); 
 204         return (wxSizerItem
*)NULL
; 
 208 wxSizerItem
* wxGridBagSizer::Add( int width
, int height
, 
 209                           const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 210                           int flag
, int border
,  wxObject
* userData 
) 
 212     wxGBSizerItem
* item 
= new wxGBSizerItem(width
, height
, pos
, span
, flag
, border
, userData
); 
 218         return (wxSizerItem
*)NULL
; 
 222 wxSizerItem
* wxGridBagSizer::Add( wxGBSizerItem 
*item 
) 
 224     wxCHECK_MSG( !CheckForIntersection(item
), NULL
, 
 225                  wxT("An item is already at that position") ); 
 226     m_children
.Append(item
); 
 227     item
->SetGBSizer(this); 
 228     if ( item
->GetWindow() ) 
 229         item
->GetWindow()->SetContainingSizer( this ); 
 236 //--------------------------------------------------------------------------- 
 238 wxSize 
wxGridBagSizer::GetCellSize(int row
, int col
) const 
 240     wxCHECK_MSG( (row 
< m_rows
) && (col 
< m_cols
), 
 242                  wxT("Invalid cell.")); 
 243     return wxSize( m_colWidths
[col
], m_rowHeights
[row
] ); 
 247 wxGBPosition 
wxGridBagSizer::GetItemPosition(wxWindow 
*window
) 
 249     wxGBPosition 
badpos(-1,-1); 
 250     wxGBSizerItem
* item 
= FindItem(window
); 
 251     wxCHECK_MSG(item
, badpos
, wxT("Failed to find item.")); 
 252     return item
->GetPos(); 
 256 wxGBPosition 
wxGridBagSizer::GetItemPosition(wxSizer 
*sizer
) 
 258     wxGBPosition 
badpos(-1,-1); 
 259     wxGBSizerItem
* item 
= FindItem(sizer
); 
 260     wxCHECK_MSG(item
, badpos
, wxT("Failed to find item.")); 
 261     return item
->GetPos(); 
 265 wxGBPosition 
wxGridBagSizer::GetItemPosition(size_t index
) 
 267     wxGBPosition 
badpos(-1,-1); 
 268     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 269     wxCHECK_MSG( node
, badpos
, _T("Failed to find item.") ); 
 270     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 271     return item
->GetPos(); 
 276 bool wxGridBagSizer::SetItemPosition(wxWindow 
*window
, const wxGBPosition
& pos
) 
 278     wxGBSizerItem
* item 
= FindItem(window
); 
 279     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 280     return item
->SetPos(pos
); 
 284 bool wxGridBagSizer::SetItemPosition(wxSizer 
*sizer
, const wxGBPosition
& pos
) 
 286     wxGBSizerItem
* item 
= FindItem(sizer
); 
 287     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 288     return item
->SetPos(pos
); 
 292 bool wxGridBagSizer::SetItemPosition(size_t index
, const wxGBPosition
& pos
) 
 294     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 295     wxCHECK_MSG( node
, false, _T("Failed to find item.") ); 
 296     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 297     return item
->SetPos(pos
); 
 302 wxGBSpan 
wxGridBagSizer::GetItemSpan(wxWindow 
*window
) 
 304     wxGBSpan 
badspan(-1,-1); 
 305     wxGBSizerItem
* item 
= FindItem(window
); 
 306     wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") ); 
 307     return item
->GetSpan(); 
 311 wxGBSpan 
wxGridBagSizer::GetItemSpan(wxSizer 
*sizer
) 
 313     wxGBSpan 
badspan(-1,-1); 
 314     wxGBSizerItem
* item 
= FindItem(sizer
); 
 315     wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") ); 
 316     return item
->GetSpan(); 
 320 wxGBSpan 
wxGridBagSizer::GetItemSpan(size_t index
) 
 322     wxGBSpan 
badspan(-1,-1); 
 323     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 324     wxCHECK_MSG( node
, badspan
, _T("Failed to find item.") ); 
 325     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 326     return item
->GetSpan(); 
 331 bool wxGridBagSizer::SetItemSpan(wxWindow 
*window
, const wxGBSpan
& span
) 
 333     wxGBSizerItem
* item 
= FindItem(window
); 
 334     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 335     return item
->SetSpan(span
); 
 339 bool wxGridBagSizer::SetItemSpan(wxSizer 
*sizer
, const wxGBSpan
& span
) 
 341     wxGBSizerItem
* item 
= FindItem(sizer
); 
 342     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 343     return item
->SetSpan(span
); 
 347 bool wxGridBagSizer::SetItemSpan(size_t index
, const wxGBSpan
& span
) 
 349     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 350     wxCHECK_MSG( node
, false, _T("Failed to find item.") ); 
 351     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 352     return item
->SetSpan(span
); 
 358 wxGBSizerItem
* wxGridBagSizer::FindItem(wxWindow
* window
) 
 360     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 363         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 364         if ( item
->GetWindow() == window 
) 
 366         node 
= node
->GetNext(); 
 372 wxGBSizerItem
* wxGridBagSizer::FindItem(wxSizer
* sizer
) 
 374     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 377         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 378         if ( item
->GetSizer() == sizer 
) 
 380         node 
= node
->GetNext(); 
 388 wxGBSizerItem
* wxGridBagSizer::FindItemAtPosition(const wxGBPosition
& pos
) 
 390     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 393         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 394         if ( item
->Intersects(pos
, wxDefaultSpan
) ) 
 396         node 
= node
->GetNext(); 
 404 wxGBSizerItem
* wxGridBagSizer::FindItemAtPoint(const wxPoint
& pt
) 
 406     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 409         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 410         wxRect 
rect(item
->GetPosition(), item
->GetSize()); 
 411         rect
.Inflate(m_hgap
, m_vgap
); 
 412         if ( rect
.Contains(pt
) ) 
 414         node 
= node
->GetNext(); 
 422 wxGBSizerItem
* wxGridBagSizer::FindItemWithData(const wxObject
* userData
) 
 424     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 427         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 428         if ( item
->GetUserData() == userData 
) 
 430         node 
= node
->GetNext(); 
 438 //--------------------------------------------------------------------------- 
 440 // Figure out what all the min row heights and col widths are, and calculate 
 441 // min size from that. 
 442 wxSize 
wxGridBagSizer::CalcMin() 
 446     if (m_children
.GetCount() == 0) 
 447         return m_emptyCellSize
; 
 449     m_rowHeights
.Empty(); 
 452     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 455         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 456         if ( item
->IsShown() ) 
 458             int row
, col
, endrow
, endcol
; 
 460             item
->GetPos(row
, col
); 
 461             item
->GetEndPos(endrow
, endcol
); 
 463             // fill heights and widths upto this item if needed 
 464             while ( m_rowHeights
.GetCount() <= (size_t)endrow 
) 
 465                 m_rowHeights
.Add(m_emptyCellSize
.GetHeight()); 
 466             while ( m_colWidths
.GetCount() <= (size_t)endcol 
) 
 467                 m_colWidths
.Add(m_emptyCellSize
.GetWidth()); 
 469             // See if this item increases the size of its row(s) or col(s) 
 470             wxSize 
size(item
->CalcMin()); 
 471             for (idx
=row
; idx 
<= endrow
; idx
++) 
 472                 m_rowHeights
[idx
] = wxMax(m_rowHeights
[idx
], size
.GetHeight() / (endrow
-row
+1)); 
 473             for (idx
=col
; idx 
<= endcol
; idx
++) 
 474                 m_colWidths
[idx
] = wxMax(m_colWidths
[idx
], size
.GetWidth() / (endcol
-col
+1)); 
 476         node 
= node
->GetNext(); 
 479     AdjustForFlexDirection(); 
 481     // Now traverse the heights and widths arrays calcing the totals, including gaps 
 483     m_cols 
= m_colWidths
.GetCount(); 
 484     for (idx
=0; idx 
< m_cols
; idx
++) 
 485         width 
+= m_colWidths
[idx
] + ( idx 
== m_cols
-1 ? 0 : m_hgap 
); 
 488     m_rows 
= m_rowHeights
.GetCount(); 
 489     for (idx
=0; idx 
< m_rows
; idx
++) 
 490         height 
+= m_rowHeights
[idx
] + ( idx 
== m_rows
-1 ? 0 : m_vgap 
); 
 492     m_calculatedMinSize 
= wxSize(width
, height
); 
 493     return m_calculatedMinSize
; 
 498 void wxGridBagSizer::RecalcSizes() 
 500     if (m_children
.GetCount() == 0) 
 503     wxPoint 
pt( GetPosition() ); 
 504     wxSize  
sz( GetSize() ); 
 506     m_rows 
= m_rowHeights
.GetCount(); 
 507     m_cols 
= m_colWidths
.GetCount(); 
 508     int idx
, width
, height
; 
 510     AdjustForGrowables(sz
); 
 512     // Find the start positions on the window of the rows and columns 
 514     rowpos
.Add(0, m_rows
); 
 516     for (idx
=0; idx 
< m_rows
; idx
++) 
 518         height 
= m_rowHeights
[idx
] + m_vgap
; 
 524     colpos
.Add(0, m_cols
); 
 526     for (idx
=0; idx 
< m_cols
; idx
++) 
 528         width 
= m_colWidths
[idx
] + m_hgap
; 
 534     // Now iterate the children, setting each child's dimensions 
 535     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 538         int row
, col
, endrow
, endcol
; 
 539         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 541         if ( item
->IsShown() ) 
 543             item
->GetPos(row
, col
); 
 544             item
->GetEndPos(endrow
, endcol
); 
 547             for(idx
=row
; idx 
<= endrow
; idx
++) 
 548                 height 
+= m_rowHeights
[idx
]; 
 549             height 
+= (endrow 
- row
) * m_vgap
; // add a vgap for every row spanned 
 552             for (idx
=col
; idx 
<= endcol
; idx
++) 
 553                 width 
+= m_colWidths
[idx
]; 
 554             width 
+= (endcol 
- col
) * m_hgap
; // add a hgap for every col spanned 
 556             SetItemBounds(item
, colpos
[col
], rowpos
[row
], width
, height
); 
 559         node 
= node
->GetNext(); 
 565 //--------------------------------------------------------------------------- 
 567 bool wxGridBagSizer::CheckForIntersection(wxGBSizerItem
* item
, wxGBSizerItem
* excludeItem
) 
 569     return CheckForIntersection(item
->GetPos(), item
->GetSpan(), excludeItem
); 
 572 bool wxGridBagSizer::CheckForIntersection(const wxGBPosition
& pos
, const wxGBSpan
& span
, wxGBSizerItem
* excludeItem
) 
 574     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 577         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 578         node 
= node
->GetNext(); 
 580         if ( excludeItem 
&& item 
== excludeItem 
) 
 583         if ( item
->Intersects(pos
, span
) ) 
 591 // Assumes a 10x10 grid, and returns the first empty cell found.  This is 
 592 // really stupid but it is only used by the Add methods that match the base 
 593 // class virtuals, which should normally not be used anyway... 
 594 wxGBPosition 
wxGridBagSizer::FindEmptyCell() 
 598     for (row
=0; row
<10; row
++) 
 599         for (col
=0; col
<10; col
++) 
 601             wxGBPosition 
pos(row
, col
); 
 602             if ( !CheckForIntersection(pos
, wxDefaultSpan
) ) 
 605     return wxGBPosition(-1, -1); 
 609 //--------------------------------------------------------------------------- 
 611 // The Add base class virtuals should not be used with this class, but 
 612 // we'll try to make them automatically select a location for the item 
 615 wxSizerItem
* wxGridBagSizer::Add( wxWindow 
*window
, int, int flag
, int border
, wxObject
* userData 
) 
 617     return Add(window
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 620 wxSizerItem
* wxGridBagSizer::Add( wxSizer 
*sizer
, int, int flag
, int border
, wxObject
* userData 
) 
 622     return Add(sizer
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 625 wxSizerItem
* wxGridBagSizer::Add( int width
, int height
, int, int flag
, int border
, wxObject
* userData 
) 
 627     return Add(width
, height
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 632 // The Insert nad Prepend base class virtuals that are not appropriate for 
 633 // this class and should not be used.  Their implementation in this class 
 636 wxSizerItem
* wxGridBagSizer::Add( wxSizerItem 
* ) 
 638     wxFAIL_MSG(wxT("Invalid Add form called.")); 
 639     return (wxSizerItem
*)NULL
; 
 642 wxSizerItem
* wxGridBagSizer::Prepend( wxWindow 
*, int, int, int, wxObject
*  ) 
 644     wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); 
 645     return (wxSizerItem
*)NULL
; 
 648 wxSizerItem
* wxGridBagSizer::Prepend( wxSizer 
*, int, int, int, wxObject
*  ) 
 650     wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); 
 651     return (wxSizerItem
*)NULL
; 
 654 wxSizerItem
* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject
*  ) 
 656     wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); 
 657     return (wxSizerItem
*)NULL
; 
 660 wxSizerItem
* wxGridBagSizer::Prepend( wxSizerItem 
* ) 
 662     wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); 
 663     return (wxSizerItem
*)NULL
; 
 667 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxWindow 
*, int, int, int, wxObject
*  ) 
 669     wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); 
 670     return (wxSizerItem
*)NULL
; 
 673 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxSizer 
*, int, int, int, wxObject
*  ) 
 675     wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); 
 676     return (wxSizerItem
*)NULL
; 
 679 wxSizerItem
* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject
*  ) 
 681     wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); 
 682     return (wxSizerItem
*)NULL
; 
 685 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxSizerItem 
* ) 
 687     wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); 
 688     return (wxSizerItem
*)NULL
; 
 692 //--------------------------------------------------------------------------- 
 693 //---------------------------------------------------------------------------