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_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
),
82 //---------------------------------------------------------------------------
85 void wxGBSizerItem::GetPos(int& row
, int& col
) const
91 void wxGBSizerItem::GetSpan(int& rowspan
, int& colspan
) const
93 rowspan
= m_span
.GetRowspan();
94 colspan
= m_span
.GetColspan();
98 bool wxGBSizerItem::SetPos( const wxGBPosition
& pos
)
102 wxCHECK_MSG( !m_sizer
->CheckForIntersection(pos
, m_span
, this), false,
103 wxT("An item is already at that position") );
109 bool wxGBSizerItem::SetSpan( const wxGBSpan
& span
)
113 wxCHECK_MSG( !m_sizer
->CheckForIntersection(m_pos
, span
, this), false,
114 wxT("An item is already at that position") );
121 inline bool InRange(int val
, int min
, int max
)
123 return (val
>= min
&& val
<= max
);
126 bool wxGBSizerItem::Intersects(const wxGBSizerItem
& other
)
128 return Intersects(other
.GetPos(), other
.GetSpan());
131 bool wxGBSizerItem::Intersects(const wxGBPosition
& pos
, const wxGBSpan
& span
)
134 int row
, col
, endrow
, endcol
;
135 int otherrow
, othercol
, otherendrow
, otherendcol
;
138 GetEndPos(endrow
, endcol
);
140 otherrow
= pos
.GetRow();
141 othercol
= pos
.GetCol();
142 otherendrow
= otherrow
+ span
.GetRowspan() - 1;
143 otherendcol
= othercol
+ span
.GetColspan() - 1;
145 // is the other item's start or end in the range of this one?
146 if (( InRange(otherrow
, row
, endrow
) && InRange(othercol
, col
, endcol
) ) ||
147 ( InRange(otherendrow
, row
, endrow
) && InRange(otherendcol
, col
, endcol
) ))
150 // is this item's start or end in the range of the other one?
151 if (( InRange(row
, otherrow
, otherendrow
) && InRange(col
, othercol
, otherendcol
) ) ||
152 ( InRange(endrow
, otherrow
, otherendrow
) && InRange(endcol
, othercol
, otherendcol
) ))
159 void wxGBSizerItem::GetEndPos(int& row
, int& col
)
161 row
= m_pos
.GetRow() + m_span
.GetRowspan() - 1;
162 col
= m_pos
.GetCol() + m_span
.GetColspan() - 1;
166 //---------------------------------------------------------------------------
168 //---------------------------------------------------------------------------
170 wxGridBagSizer::wxGridBagSizer(int vgap
, int hgap
)
171 : wxFlexGridSizer(1, vgap
, hgap
),
172 m_emptyCellSize(10,20)
178 bool wxGridBagSizer::Add( wxWindow
*window
,
179 const wxGBPosition
& pos
, const wxGBSpan
& span
,
180 int flag
, int border
, wxObject
* userData
)
182 wxGBSizerItem
* item
= new wxGBSizerItem(window
, pos
, span
, flag
, border
, userData
);
192 bool wxGridBagSizer::Add( wxSizer
*sizer
,
193 const wxGBPosition
& pos
, const wxGBSpan
& span
,
194 int flag
, int border
, wxObject
* userData
)
196 wxGBSizerItem
* item
= new wxGBSizerItem(sizer
, pos
, span
, flag
, border
, userData
);
206 bool wxGridBagSizer::Add( int width
, int height
,
207 const wxGBPosition
& pos
, const wxGBSpan
& span
,
208 int flag
, int border
, wxObject
* userData
)
210 wxGBSizerItem
* item
= new wxGBSizerItem(width
, height
, pos
, span
, flag
, border
, userData
);
220 bool wxGridBagSizer::Add( wxGBSizerItem
*item
)
222 m_children
.Append(item
);
223 item
->SetSizer(this);
224 if ( item
->GetWindow() )
225 item
->GetWindow()->SetContainingSizer( this );
232 //---------------------------------------------------------------------------
234 wxGBPosition
wxGridBagSizer::GetItemPosition(wxWindow
*window
)
236 wxGBPosition
badpos(-1,-1);
237 wxGBSizerItem
* item
= FindItem(window
);
238 wxCHECK_MSG(item
, badpos
, wxT("Failed to find item."));
239 return item
->GetPos();
243 wxGBPosition
wxGridBagSizer::GetItemPosition(wxSizer
*sizer
)
245 wxGBPosition
badpos(-1,-1);
246 wxGBSizerItem
* item
= FindItem(sizer
);
247 wxCHECK_MSG(item
, badpos
, wxT("Failed to find item."));
248 return item
->GetPos();
252 wxGBPosition
wxGridBagSizer::GetItemPosition(size_t index
)
254 wxGBPosition
badpos(-1,-1);
255 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
256 wxCHECK_MSG( node
, badpos
, _T("Failed to find item.") );
257 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
258 return item
->GetPos();
263 bool wxGridBagSizer::SetItemPosition(wxWindow
*window
, const wxGBPosition
& pos
)
265 wxGBSizerItem
* item
= FindItem(window
);
266 wxCHECK_MSG(item
, false, wxT("Failed to find item."));
267 return item
->SetPos(pos
);
271 bool wxGridBagSizer::SetItemPosition(wxSizer
*sizer
, const wxGBPosition
& pos
)
273 wxGBSizerItem
* item
= FindItem(sizer
);
274 wxCHECK_MSG(item
, false, wxT("Failed to find item."));
275 return item
->SetPos(pos
);
279 bool wxGridBagSizer::SetItemPosition(size_t index
, const wxGBPosition
& pos
)
281 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
282 wxCHECK_MSG( node
, false, _T("Failed to find item.") );
283 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
284 return item
->SetPos(pos
);
289 wxGBSpan
wxGridBagSizer::GetItemSpan(wxWindow
*window
)
291 wxGBSpan
badspan(-1,-1);
292 wxGBSizerItem
* item
= FindItem(window
);
293 wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") );
294 return item
->GetSpan();
298 wxGBSpan
wxGridBagSizer::GetItemSpan(wxSizer
*sizer
)
300 wxGBSpan
badspan(-1,-1);
301 wxGBSizerItem
* item
= FindItem(sizer
);
302 wxCHECK_MSG( item
, badspan
, _T("Failed to find item.") );
303 return item
->GetSpan();
307 wxGBSpan
wxGridBagSizer::GetItemSpan(size_t index
)
309 wxGBSpan
badspan(-1,-1);
310 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
311 wxCHECK_MSG( node
, badspan
, _T("Failed to find item.") );
312 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
313 return item
->GetSpan();
318 bool wxGridBagSizer::SetItemSpan(wxWindow
*window
, const wxGBSpan
& span
)
320 wxGBSizerItem
* item
= FindItem(window
);
321 wxCHECK_MSG(item
, false, wxT("Failed to find item."));
322 return item
->SetSpan(span
);
326 bool wxGridBagSizer::SetItemSpan(wxSizer
*sizer
, const wxGBSpan
& span
)
328 wxGBSizerItem
* item
= FindItem(sizer
);
329 wxCHECK_MSG(item
, false, wxT("Failed to find item."));
330 return item
->SetSpan(span
);
334 bool wxGridBagSizer::SetItemSpan(size_t index
, const wxGBSpan
& span
)
336 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
337 wxCHECK_MSG( node
, false, _T("Failed to find item.") );
338 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
339 return item
->SetSpan(span
);
345 wxGBSizerItem
* wxGridBagSizer::FindItem(wxWindow
* window
)
347 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
350 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
351 if ( item
->GetWindow() == window
)
353 node
= node
->GetNext();
359 wxGBSizerItem
* wxGridBagSizer::FindItem(wxSizer
* sizer
)
361 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
364 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
365 if ( item
->GetSizer() == sizer
)
367 node
= node
->GetNext();
375 wxGBSizerItem
* wxGridBagSizer::FindItemAtPosition(const wxGBPosition
& pos
)
377 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
380 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
381 if ( item
->Intersects(pos
, wxDefaultSpan
) )
383 node
= node
->GetNext();
391 wxGBSizerItem
* wxGridBagSizer::FindItemWithData(const wxObject
* userData
)
393 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
396 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
397 if ( item
->GetUserData() == userData
)
399 node
= node
->GetNext();
407 //---------------------------------------------------------------------------
409 // Figure out what all the min row heights and col widths are, and calculate
410 // min size from that.
411 wxSize
wxGridBagSizer::CalcMin()
415 if (m_children
.GetCount() == 0)
416 return m_emptyCellSize
;
418 m_rowHeights
.Empty();
421 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
424 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
425 if ( item
->IsShown() )
427 int row
, col
, endrow
, endcol
;
429 item
->GetPos(row
, col
);
430 item
->GetEndPos(endrow
, endcol
);
432 // fill heights and widths upto this item if needed
433 while ( m_rowHeights
.GetCount() <= (size_t)endrow
)
434 m_rowHeights
.Add(m_emptyCellSize
.GetHeight());
435 while ( m_colWidths
.GetCount() <= (size_t)endcol
)
436 m_colWidths
.Add(m_emptyCellSize
.GetWidth());
438 // See if this item increases the size of its row(s) or col(s)
439 wxSize
size(item
->CalcMin());
440 for (idx
=row
; idx
<= endrow
; idx
++)
441 m_rowHeights
[idx
] = wxMax(m_rowHeights
[idx
], size
.GetHeight() / (endrow
-row
+1));
442 for (idx
=col
; idx
<= endcol
; idx
++)
443 m_colWidths
[idx
] = wxMax(m_colWidths
[idx
], size
.GetWidth() / (endcol
-col
+1));
445 node
= node
->GetNext();
448 AdjustForFlexDirection();
450 // Now traverse the heights and widths arrays calcing the totals, including gaps
452 int ncols
= m_colWidths
.GetCount();
453 for (idx
=0; idx
< ncols
; idx
++)
454 width
+= m_colWidths
[idx
] + ( idx
== ncols
-1 ? 0 : m_hgap
);
457 int nrows
= m_rowHeights
.GetCount();
458 for (idx
=0; idx
< nrows
; idx
++)
459 height
+= m_rowHeights
[idx
] + ( idx
== nrows
-1 ? 0 : m_vgap
);
461 return wxSize(width
, height
);
466 void wxGridBagSizer::RecalcSizes()
468 if (m_children
.GetCount() == 0)
471 // Calculates minsize and populates m_rowHeights and m_colWidths
472 wxSize
minsz( CalcMin() );
474 wxPoint
pt( GetPosition() );
475 wxSize
sz( GetSize() );
477 int nrows
= m_rowHeights
.GetCount();
478 int ncols
= m_colWidths
.GetCount();
479 int idx
, width
, height
;
481 AdjustForGrowables(sz
, minsz
, nrows
, ncols
);
483 // Find the start positions on the window of the rows and columns
485 rowpos
.Add(0, nrows
);
487 for (idx
=0; idx
< nrows
; idx
++)
489 height
= m_rowHeights
[idx
] + m_vgap
;
495 colpos
.Add(0, ncols
);
497 for (idx
=0; idx
< ncols
; idx
++)
499 width
= m_colWidths
[idx
] + m_hgap
;
505 // Now iterate the children, setting each child's dimensions
506 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
509 int row
, col
, endrow
, endcol
;
510 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
511 item
->GetPos(row
, col
);
512 item
->GetEndPos(endrow
, endcol
);
515 for(idx
=row
; idx
<= endrow
; idx
++)
516 height
+= m_rowHeights
[idx
] + m_vgap
;
519 for (idx
=col
; idx
<= endcol
; idx
++)
520 width
+= m_colWidths
[idx
] + m_hgap
;
522 SetItemBounds(item
, colpos
[col
], rowpos
[row
], width
, height
);
524 node
= node
->GetNext();
530 //---------------------------------------------------------------------------
532 bool wxGridBagSizer::CheckForIntersection(wxGBSizerItem
* item
, wxGBSizerItem
* excludeItem
)
534 return CheckForIntersection(item
->GetPos(), item
->GetSpan(), excludeItem
);
537 bool wxGridBagSizer::CheckForIntersection(const wxGBPosition
& pos
, const wxGBSpan
& span
, wxGBSizerItem
* excludeItem
)
539 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
542 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
543 node
= node
->GetNext();
545 if ( excludeItem
&& item
== excludeItem
)
548 if ( item
->Intersects(pos
, span
) )
556 // Assumes a 10x10 grid, and returns the first empty cell found. This is
557 // really stupid but it is only used by the Add methods that match the base
558 // class virtuals, which should normally not be used anyway...
559 wxGBPosition
wxGridBagSizer::FindEmptyCell()
563 for (row
=0; row
<10; row
++)
564 for (col
=0; col
<10; col
++)
566 wxGBPosition
pos(row
, col
);
567 if ( !CheckForIntersection(pos
, wxDefaultSpan
) )
570 return wxGBPosition(-1, -1);
574 //---------------------------------------------------------------------------
576 // The Add base class virtuals should not be used with this class, but
577 // we'll try to make them automatically select a location for the item
580 void wxGridBagSizer::Add( wxWindow
*window
, int, int flag
, int border
, wxObject
* userData
)
582 Add(window
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
585 void wxGridBagSizer::Add( wxSizer
*sizer
, int, int flag
, int border
, wxObject
* userData
)
587 Add(sizer
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
590 void wxGridBagSizer::Add( int width
, int height
, int, int flag
, int border
, wxObject
* userData
)
592 Add(width
, height
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
597 // The Insert nad Prepend base class virtuals that are not appropriate for
598 // this class and should not be used. Their implementation in this class
601 void wxGridBagSizer::Add( wxSizerItem
*item
)
602 { wxFAIL_MSG(wxT("Invalid Add form called.")); }
604 void wxGridBagSizer::Prepend( wxWindow
*, int, int, int, wxObject
* )
605 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); }
607 void wxGridBagSizer::Prepend( wxSizer
*, int, int, int, wxObject
* )
608 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); }
610 void wxGridBagSizer::Prepend( int, int, int, int, int, wxObject
* )
611 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); }
613 void wxGridBagSizer::Prepend( wxSizerItem
* )
614 { wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); }
617 void wxGridBagSizer::Insert( size_t, wxWindow
*, int, int, int, wxObject
* )
618 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); }
620 void wxGridBagSizer::Insert( size_t, wxSizer
*, int, int, int, wxObject
* )
621 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); }
623 void wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject
* )
624 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); }
626 void wxGridBagSizer::Insert( size_t, wxSizerItem
* )
627 { wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); }
630 //---------------------------------------------------------------------------
631 //---------------------------------------------------------------------------