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 ///////////////////////////////////////////////////////////////////////////// 
  15 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  16 #pragma implementation "gbsizer.h" 
  19 // For compilers that support precompilation, includes "wx.h". 
  20 #include "wx/wxprec.h" 
  26 #include "wx/gbsizer.h" 
  28 //--------------------------------------------------------------------------- 
  30 IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem
, wxSizerItem
) 
  31 IMPLEMENT_CLASS(wxGridBagSizer
, wxFlexGridSizer
) 
  33 const wxGBSpan wxDefaultSpan
; 
  35 //--------------------------------------------------------------------------- 
  37 //--------------------------------------------------------------------------- 
  39 wxGBSizerItem::wxGBSizerItem( int width
, 
  41                               const wxGBPosition
& pos
, 
  46     : wxSizerItem(width
, height
, 0, flag
, border
, userData
), 
  54 wxGBSizerItem::wxGBSizerItem( wxWindow 
*window
, 
  55                               const wxGBPosition
& pos
, 
  60     : wxSizerItem(window
, 0, flag
, border
, userData
), 
  68 wxGBSizerItem::wxGBSizerItem( wxSizer 
*sizer
, 
  69                               const wxGBPosition
& pos
, 
  74     : wxSizerItem(sizer
, 0, flag
, border
, userData
), 
  81 wxGBSizerItem::wxGBSizerItem() 
  89 //--------------------------------------------------------------------------- 
  92 void wxGBSizerItem::GetPos(int& row
, int& col
) const 
  98 void wxGBSizerItem::GetSpan(int& rowspan
, int& colspan
) const 
 100     rowspan 
= m_span
.GetRowspan(); 
 101     colspan 
= m_span
.GetColspan(); 
 105 bool wxGBSizerItem::SetPos( const wxGBPosition
& pos 
) 
 109         wxCHECK_MSG( !m_gbsizer
->CheckForIntersection(pos
, m_span
, this), false, 
 110                  wxT("An item is already at that position") ); 
 116 bool wxGBSizerItem::SetSpan( const wxGBSpan
& span 
) 
 120         wxCHECK_MSG( !m_gbsizer
->CheckForIntersection(m_pos
, span
, this), false, 
 121                  wxT("An item is already at that position") ); 
 128 inline bool InRange(int val
, int min
, int max
) 
 130     return (val 
>= min 
&& val 
<= max
); 
 133 bool wxGBSizerItem::Intersects(const wxGBSizerItem
& other
) 
 135     return Intersects(other
.GetPos(), other
.GetSpan()); 
 138 bool wxGBSizerItem::Intersects(const wxGBPosition
& pos
, const wxGBSpan
& span
) 
 141     int row
, col
, endrow
, endcol
; 
 142     int otherrow
, othercol
, otherendrow
, otherendcol
; 
 145     GetEndPos(endrow
, endcol
); 
 147     otherrow 
= pos
.GetRow(); 
 148     othercol 
= pos
.GetCol(); 
 149     otherendrow 
= otherrow 
+ span
.GetRowspan() - 1; 
 150     otherendcol 
= othercol 
+ span
.GetColspan() - 1; 
 152     // is the other item's start or end in the range of this one? 
 153     if (( InRange(otherrow
, row
, endrow
) && InRange(othercol
, col
, endcol
) ) || 
 154         ( InRange(otherendrow
, row
, endrow
) && InRange(otherendcol
, col
, endcol
) )) 
 157     // is this item's start or end in the range of the other one? 
 158     if (( InRange(row
, otherrow
, otherendrow
) && InRange(col
, othercol
, otherendcol
) ) || 
 159         ( InRange(endrow
, otherrow
, otherendrow
) && InRange(endcol
, othercol
, otherendcol
) )) 
 166 void wxGBSizerItem::GetEndPos(int& row
, int& col
) 
 168     row 
= m_pos
.GetRow() + m_span
.GetRowspan() - 1; 
 169     col 
= m_pos
.GetCol() + m_span
.GetColspan() - 1; 
 173 //--------------------------------------------------------------------------- 
 175 //--------------------------------------------------------------------------- 
 177 wxGridBagSizer::wxGridBagSizer(int vgap
, int hgap 
) 
 178     : wxFlexGridSizer(1, vgap
, hgap
), 
 179       m_emptyCellSize(10,20) 
 185 bool wxGridBagSizer::Add( wxWindow 
*window
, 
 186                           const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 187                           int flag
, int border
,  wxObject
* userData 
) 
 189     wxGBSizerItem
* item 
= new wxGBSizerItem(window
, pos
, span
, flag
, border
, userData
); 
 199 bool wxGridBagSizer::Add( wxSizer 
*sizer
, 
 200                           const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 201                           int flag
, int border
,  wxObject
* userData 
) 
 203     wxGBSizerItem
* item 
= new wxGBSizerItem(sizer
, pos
, span
, flag
, border
, userData
); 
 213 bool wxGridBagSizer::Add( int width
, int height
, 
 214                           const wxGBPosition
& pos
, const wxGBSpan
& span
, 
 215                           int flag
, int border
,  wxObject
* userData 
) 
 217     wxGBSizerItem
* item 
= new wxGBSizerItem(width
, height
, pos
, span
, flag
, border
, userData
); 
 227 bool wxGridBagSizer::Add( wxGBSizerItem 
*item 
) 
 229     wxCHECK_MSG( !CheckForIntersection(item
), false, 
 230                  wxT("An item is already at that position") ); 
 231     m_children
.Append(item
); 
 232     item
->SetGBSizer(this); 
 233     if ( item
->GetWindow() ) 
 234         item
->GetWindow()->SetContainingSizer( this ); 
 241 //--------------------------------------------------------------------------- 
 243 wxSize 
wxGridBagSizer::GetCellSize(int row
, int col
) const 
 245     wxCHECK_MSG( (row 
< m_rows
) && (col 
< m_cols
), 
 247                  wxT("Invalid cell.")); 
 248     return wxSize( m_colWidths
[col
], m_rowHeights
[row
] ); 
 252 wxGBPosition 
wxGridBagSizer::GetItemPosition(wxWindow 
*window
) 
 254     wxGBPosition 
badpos(-1,-1); 
 255     wxGBSizerItem
* item 
= FindItem(window
); 
 256     wxCHECK_MSG(item
, badpos
, wxT("Failed to find item.")); 
 257     return item
->GetPos(); 
 261 wxGBPosition 
wxGridBagSizer::GetItemPosition(wxSizer 
*sizer
) 
 263     wxGBPosition 
badpos(-1,-1); 
 264     wxGBSizerItem
* item 
= FindItem(sizer
); 
 265     wxCHECK_MSG(item
, badpos
, wxT("Failed to find item.")); 
 266     return item
->GetPos(); 
 270 wxGBPosition 
wxGridBagSizer::GetItemPosition(size_t index
) 
 272     wxGBPosition 
badpos(-1,-1); 
 273     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 274     wxCHECK_MSG( node
, badpos
, _T("Failed to find item.") ); 
 275     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 276     return item
->GetPos(); 
 281 bool wxGridBagSizer::SetItemPosition(wxWindow 
*window
, const wxGBPosition
& pos
) 
 283     wxGBSizerItem
* item 
= FindItem(window
); 
 284     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 285     return item
->SetPos(pos
); 
 289 bool wxGridBagSizer::SetItemPosition(wxSizer 
*sizer
, const wxGBPosition
& pos
) 
 291     wxGBSizerItem
* item 
= FindItem(sizer
); 
 292     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 293     return item
->SetPos(pos
); 
 297 bool wxGridBagSizer::SetItemPosition(size_t index
, const wxGBPosition
& pos
) 
 299     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 300     wxCHECK_MSG( node
, false, _T("Failed to find item.") ); 
 301     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 302     return item
->SetPos(pos
); 
 307 wxGBSpan 
wxGridBagSizer::GetItemSpan(wxWindow 
*window
) 
 309     wxGBSpan 
badspan(-1,-1); 
 310     wxGBSizerItem
* item 
= FindItem(window
); 
 311     wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") ); 
 312     return item
->GetSpan(); 
 316 wxGBSpan 
wxGridBagSizer::GetItemSpan(wxSizer 
*sizer
) 
 318     wxGBSpan 
badspan(-1,-1); 
 319     wxGBSizerItem
* item 
= FindItem(sizer
); 
 320     wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") ); 
 321     return item
->GetSpan(); 
 325 wxGBSpan 
wxGridBagSizer::GetItemSpan(size_t index
) 
 327     wxGBSpan 
badspan(-1,-1); 
 328     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 329     wxCHECK_MSG( node
, badspan
, _T("Failed to find item.") ); 
 330     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 331     return item
->GetSpan(); 
 336 bool wxGridBagSizer::SetItemSpan(wxWindow 
*window
, const wxGBSpan
& span
) 
 338     wxGBSizerItem
* item 
= FindItem(window
); 
 339     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 340     return item
->SetSpan(span
); 
 344 bool wxGridBagSizer::SetItemSpan(wxSizer 
*sizer
, const wxGBSpan
& span
) 
 346     wxGBSizerItem
* item 
= FindItem(sizer
); 
 347     wxCHECK_MSG(item
, false, wxT("Failed to find item.")); 
 348     return item
->SetSpan(span
); 
 352 bool wxGridBagSizer::SetItemSpan(size_t index
, const wxGBSpan
& span
) 
 354     wxSizerItemList::compatibility_iterator node 
= m_children
.Item( index 
); 
 355     wxCHECK_MSG( node
, false, _T("Failed to find item.") ); 
 356     wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 357     return item
->SetSpan(span
); 
 363 wxGBSizerItem
* wxGridBagSizer::FindItem(wxWindow
* window
) 
 365     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 368         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 369         if ( item
->GetWindow() == window 
) 
 371         node 
= node
->GetNext(); 
 377 wxGBSizerItem
* wxGridBagSizer::FindItem(wxSizer
* sizer
) 
 379     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 382         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 383         if ( item
->GetSizer() == sizer 
) 
 385         node 
= node
->GetNext(); 
 393 wxGBSizerItem
* wxGridBagSizer::FindItemAtPosition(const wxGBPosition
& pos
) 
 395     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 398         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 399         if ( item
->Intersects(pos
, wxDefaultSpan
) ) 
 401         node 
= node
->GetNext(); 
 409 wxGBSizerItem
* wxGridBagSizer::FindItemAtPoint(const wxPoint
& pt
) 
 411     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 414         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 415         wxRect 
rect(item
->GetPosition(), item
->GetSize()); 
 416         rect
.Inflate(m_hgap
, m_vgap
); 
 417         if ( rect
.Inside(pt
) ) 
 419         node 
= node
->GetNext(); 
 427 wxGBSizerItem
* wxGridBagSizer::FindItemWithData(const wxObject
* userData
) 
 429     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 432         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 433         if ( item
->GetUserData() == userData 
) 
 435         node 
= node
->GetNext(); 
 443 //--------------------------------------------------------------------------- 
 445 // Figure out what all the min row heights and col widths are, and calculate 
 446 // min size from that. 
 447 wxSize 
wxGridBagSizer::CalcMin() 
 451     if (m_children
.GetCount() == 0) 
 452         return m_emptyCellSize
; 
 454     m_rowHeights
.Empty(); 
 457     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 460         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 461         if ( item
->IsShown() ) 
 463             int row
, col
, endrow
, endcol
; 
 465             item
->GetPos(row
, col
); 
 466             item
->GetEndPos(endrow
, endcol
); 
 468             // fill heights and widths upto this item if needed 
 469             while ( m_rowHeights
.GetCount() <= (size_t)endrow 
) 
 470                 m_rowHeights
.Add(m_emptyCellSize
.GetHeight()); 
 471             while ( m_colWidths
.GetCount() <= (size_t)endcol 
) 
 472                 m_colWidths
.Add(m_emptyCellSize
.GetWidth()); 
 474             // See if this item increases the size of its row(s) or col(s) 
 475             wxSize 
size(item
->CalcMin()); 
 476             for (idx
=row
; idx 
<= endrow
; idx
++) 
 477                 m_rowHeights
[idx
] = wxMax(m_rowHeights
[idx
], size
.GetHeight() / (endrow
-row
+1)); 
 478             for (idx
=col
; idx 
<= endcol
; idx
++) 
 479                 m_colWidths
[idx
] = wxMax(m_colWidths
[idx
], size
.GetWidth() / (endcol
-col
+1)); 
 481         node 
= node
->GetNext(); 
 484     AdjustForFlexDirection(); 
 486     // Now traverse the heights and widths arrays calcing the totals, including gaps 
 488     m_cols 
= m_colWidths
.GetCount(); 
 489     for (idx
=0; idx 
< m_cols
; idx
++) 
 490         width 
+= m_colWidths
[idx
] + ( idx 
== m_cols
-1 ? 0 : m_hgap 
); 
 493     m_rows 
= m_rowHeights
.GetCount(); 
 494     for (idx
=0; idx 
< m_rows
; idx
++) 
 495         height 
+= m_rowHeights
[idx
] + ( idx 
== m_rows
-1 ? 0 : m_vgap 
); 
 497     m_calculatedMinSize 
= wxSize(width
, height
); 
 498     return m_calculatedMinSize
; 
 503 void wxGridBagSizer::RecalcSizes() 
 505     if (m_children
.GetCount() == 0) 
 508     wxPoint 
pt( GetPosition() ); 
 509     wxSize  
sz( GetSize() ); 
 511     m_rows 
= m_rowHeights
.GetCount(); 
 512     m_cols 
= m_colWidths
.GetCount(); 
 513     int idx
, width
, height
; 
 515     AdjustForGrowables(sz
, m_calculatedMinSize
, m_rows
, m_cols
); 
 517     // Find the start positions on the window of the rows and columns 
 519     rowpos
.Add(0, m_rows
); 
 521     for (idx
=0; idx 
< m_rows
; idx
++) 
 523         height 
= m_rowHeights
[idx
] + m_vgap
; 
 529     colpos
.Add(0, m_cols
); 
 531     for (idx
=0; idx 
< m_cols
; idx
++) 
 533         width 
= m_colWidths
[idx
] + m_hgap
; 
 539     // Now iterate the children, setting each child's dimensions 
 540     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 543         int row
, col
, endrow
, endcol
; 
 544         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 545         item
->GetPos(row
, col
); 
 546         item
->GetEndPos(endrow
, endcol
); 
 549         for(idx
=row
; idx 
<= endrow
; idx
++) 
 550             height 
+= m_rowHeights
[idx
]; 
 551         height 
+= (endrow 
- row
) * m_vgap
; // add a vgap for every row spanned 
 554         for (idx
=col
; idx 
<= endcol
; idx
++) 
 555             width 
+= m_colWidths
[idx
]; 
 556         width 
+= (endcol 
- col
) * m_hgap
; // add a hgap for every col spanned 
 558         SetItemBounds(item
, colpos
[col
], rowpos
[row
], width
, height
); 
 560         node 
= node
->GetNext(); 
 566 //--------------------------------------------------------------------------- 
 568 bool wxGridBagSizer::CheckForIntersection(wxGBSizerItem
* item
, wxGBSizerItem
* excludeItem
) 
 570     return CheckForIntersection(item
->GetPos(), item
->GetSpan(), excludeItem
); 
 573 bool wxGridBagSizer::CheckForIntersection(const wxGBPosition
& pos
, const wxGBSpan
& span
, wxGBSizerItem
* excludeItem
) 
 575     wxSizerItemList::compatibility_iterator node 
= m_children
.GetFirst(); 
 578         wxGBSizerItem
* item 
= (wxGBSizerItem
*)node
->GetData(); 
 579         node 
= node
->GetNext(); 
 581         if ( excludeItem 
&& item 
== excludeItem 
) 
 584         if ( item
->Intersects(pos
, span
) ) 
 592 // Assumes a 10x10 grid, and returns the first empty cell found.  This is 
 593 // really stupid but it is only used by the Add methods that match the base 
 594 // class virtuals, which should normally not be used anyway... 
 595 wxGBPosition 
wxGridBagSizer::FindEmptyCell() 
 599     for (row
=0; row
<10; row
++) 
 600         for (col
=0; col
<10; col
++) 
 602             wxGBPosition 
pos(row
, col
); 
 603             if ( !CheckForIntersection(pos
, wxDefaultSpan
) ) 
 606     return wxGBPosition(-1, -1); 
 610 //--------------------------------------------------------------------------- 
 612 // The Add base class virtuals should not be used with this class, but 
 613 // we'll try to make them automatically select a location for the item 
 616 void wxGridBagSizer::Add( wxWindow 
*window
, int, int flag
, int border
, wxObject
* userData 
) 
 618     Add(window
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 621 void wxGridBagSizer::Add( wxSizer 
*sizer
, int, int flag
, int border
, wxObject
* userData 
) 
 623     Add(sizer
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 626 void wxGridBagSizer::Add( int width
, int height
, int, int flag
, int border
, wxObject
* userData 
) 
 628     Add(width
, height
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
); 
 633 // The Insert nad Prepend base class virtuals that are not appropriate for 
 634 // this class and should not be used.  Their implementation in this class 
 637 void wxGridBagSizer::Add( wxSizerItem 
* ) 
 638 { wxFAIL_MSG(wxT("Invalid Add form called.")); } 
 640 void wxGridBagSizer::Prepend( wxWindow 
*, int, int, int, wxObject
*  ) 
 641 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } 
 643 void wxGridBagSizer::Prepend( wxSizer 
*, int, int, int, wxObject
*  ) 
 644 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } 
 646 void wxGridBagSizer::Prepend( int, int, int, int, int, wxObject
*  ) 
 647 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } 
 649 void wxGridBagSizer::Prepend( wxSizerItem 
* ) 
 650 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } 
 653 void wxGridBagSizer::Insert( size_t, wxWindow 
*, int, int, int, wxObject
*  ) 
 654 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } 
 656 void wxGridBagSizer::Insert( size_t, wxSizer 
*, int, int, int, wxObject
*  ) 
 657 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } 
 659 void wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject
*  ) 
 660 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } 
 662 void wxGridBagSizer::Insert( size_t, wxSizerItem 
* ) 
 663 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } 
 666 //--------------------------------------------------------------------------- 
 667 //---------------------------------------------------------------------------