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
.Inside(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
, m_calculatedMinSize
, m_rows
, m_cols
);
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();
540 item
->GetPos(row
, col
);
541 item
->GetEndPos(endrow
, endcol
);
544 for(idx
=row
; idx
<= endrow
; idx
++)
545 height
+= m_rowHeights
[idx
];
546 height
+= (endrow
- row
) * m_vgap
; // add a vgap for every row spanned
549 for (idx
=col
; idx
<= endcol
; idx
++)
550 width
+= m_colWidths
[idx
];
551 width
+= (endcol
- col
) * m_hgap
; // add a hgap for every col spanned
553 SetItemBounds(item
, colpos
[col
], rowpos
[row
], width
, height
);
555 node
= node
->GetNext();
561 //---------------------------------------------------------------------------
563 bool wxGridBagSizer::CheckForIntersection(wxGBSizerItem
* item
, wxGBSizerItem
* excludeItem
)
565 return CheckForIntersection(item
->GetPos(), item
->GetSpan(), excludeItem
);
568 bool wxGridBagSizer::CheckForIntersection(const wxGBPosition
& pos
, const wxGBSpan
& span
, wxGBSizerItem
* excludeItem
)
570 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
573 wxGBSizerItem
* item
= (wxGBSizerItem
*)node
->GetData();
574 node
= node
->GetNext();
576 if ( excludeItem
&& item
== excludeItem
)
579 if ( item
->Intersects(pos
, span
) )
587 // Assumes a 10x10 grid, and returns the first empty cell found. This is
588 // really stupid but it is only used by the Add methods that match the base
589 // class virtuals, which should normally not be used anyway...
590 wxGBPosition
wxGridBagSizer::FindEmptyCell()
594 for (row
=0; row
<10; row
++)
595 for (col
=0; col
<10; col
++)
597 wxGBPosition
pos(row
, col
);
598 if ( !CheckForIntersection(pos
, wxDefaultSpan
) )
601 return wxGBPosition(-1, -1);
605 //---------------------------------------------------------------------------
607 // The Add base class virtuals should not be used with this class, but
608 // we'll try to make them automatically select a location for the item
611 wxSizerItem
* wxGridBagSizer::Add( wxWindow
*window
, int, int flag
, int border
, wxObject
* userData
)
613 return Add(window
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
616 wxSizerItem
* wxGridBagSizer::Add( wxSizer
*sizer
, int, int flag
, int border
, wxObject
* userData
)
618 return Add(sizer
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
621 wxSizerItem
* wxGridBagSizer::Add( int width
, int height
, int, int flag
, int border
, wxObject
* userData
)
623 return Add(width
, height
, FindEmptyCell(), wxDefaultSpan
, flag
, border
, userData
);
628 // The Insert nad Prepend base class virtuals that are not appropriate for
629 // this class and should not be used. Their implementation in this class
632 wxSizerItem
* wxGridBagSizer::Add( wxSizerItem
* )
634 wxFAIL_MSG(wxT("Invalid Add form called."));
635 return (wxSizerItem
*)NULL
;
638 wxSizerItem
* wxGridBagSizer::Prepend( wxWindow
*, int, int, int, wxObject
* )
640 wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer."));
641 return (wxSizerItem
*)NULL
;
644 wxSizerItem
* wxGridBagSizer::Prepend( wxSizer
*, int, int, int, wxObject
* )
646 wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer."));
647 return (wxSizerItem
*)NULL
;
650 wxSizerItem
* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject
* )
652 wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer."));
653 return (wxSizerItem
*)NULL
;
656 wxSizerItem
* wxGridBagSizer::Prepend( wxSizerItem
* )
658 wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer."));
659 return (wxSizerItem
*)NULL
;
663 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxWindow
*, int, int, int, wxObject
* )
665 wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer."));
666 return (wxSizerItem
*)NULL
;
669 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxSizer
*, int, int, int, wxObject
* )
671 wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer."));
672 return (wxSizerItem
*)NULL
;
675 wxSizerItem
* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject
* )
677 wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer."));
678 return (wxSizerItem
*)NULL
;
681 wxSizerItem
* wxGridBagSizer::Insert( size_t, wxSizerItem
* )
683 wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer."));
684 return (wxSizerItem
*)NULL
;
688 //---------------------------------------------------------------------------
689 //---------------------------------------------------------------------------