X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1b52f7aba0dce7c2a1d26d41a930856b93b02870..603cfe42185349e119ba4c69bd56a79998babcc4:/src/common/gbsizer.cpp?ds=sidebyside diff --git a/src/common/gbsizer.cpp b/src/common/gbsizer.cpp index a43ee497a6..d9451c0983 100644 --- a/src/common/gbsizer.cpp +++ b/src/common/gbsizer.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: gbsizer.cpp +// Name: src/common/gbsizer.cpp // Purpose: wxGridBagSizer: A sizer that can lay out items in a grid, // with items at specified cells, and with the option of row // and/or column spanning @@ -11,11 +11,6 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// - -#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) -#pragma implementation "gbsizer.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -46,7 +41,7 @@ wxGBSizerItem::wxGBSizerItem( int width, : wxSizerItem(width, height, 0, flag, border, userData), m_pos(pos), m_span(span), - m_sizer(NULL) + m_gbsizer(NULL) { } @@ -60,7 +55,7 @@ wxGBSizerItem::wxGBSizerItem( wxWindow *window, : wxSizerItem(window, 0, flag, border, userData), m_pos(pos), m_span(span), - m_sizer(NULL) + m_gbsizer(NULL) { } @@ -74,15 +69,14 @@ wxGBSizerItem::wxGBSizerItem( wxSizer *sizer, : wxSizerItem(sizer, 0, flag, border, userData), m_pos(pos), m_span(span), - m_sizer(NULL) + m_gbsizer(NULL) { } wxGBSizerItem::wxGBSizerItem() : wxSizerItem(), m_pos(-1,-1), - m_span(-1,-1), - m_sizer(NULL) + m_gbsizer(NULL) { } @@ -104,9 +98,9 @@ void wxGBSizerItem::GetSpan(int& rowspan, int& colspan) const bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) { - if (m_sizer) + if (m_gbsizer) { - wxCHECK_MSG( !m_sizer->CheckForIntersection(pos, m_span, this), false, + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(pos, m_span, this), false, wxT("An item is already at that position") ); } m_pos = pos; @@ -115,9 +109,9 @@ bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) bool wxGBSizerItem::SetSpan( const wxGBSpan& span ) { - if (m_sizer) + if (m_gbsizer) { - wxCHECK_MSG( !m_sizer->CheckForIntersection(m_pos, span, this), false, + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(m_pos, span, this), false, wxT("An item is already at that position") ); } m_span = span; @@ -177,67 +171,90 @@ void wxGBSizerItem::GetEndPos(int& row, int& col) wxGridBagSizer::wxGridBagSizer(int vgap, int hgap ) : wxFlexGridSizer(1, vgap, hgap), m_emptyCellSize(10,20) - + { } -bool wxGridBagSizer::Add( wxWindow *window, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) { wxGBSizerItem* item = new wxGBSizerItem(window, pos, span, flag, border, userData); if ( Add(item) ) - return true; + return item; else { delete item; - return false; + return NULL; } } -bool wxGridBagSizer::Add( wxSizer *sizer, +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, const wxGBPosition& pos, const wxGBSpan& span, int flag, int border, wxObject* userData ) { wxGBSizerItem* item = new wxGBSizerItem(sizer, pos, span, flag, border, userData); if ( Add(item) ) - return true; + return item; else { delete item; - return false; + return NULL; } } -bool wxGridBagSizer::Add( int width, int height, +wxSizerItem* wxGridBagSizer::Add( int width, int height, const wxGBPosition& pos, const wxGBSpan& span, int flag, int border, wxObject* userData ) { wxGBSizerItem* item = new wxGBSizerItem(width, height, pos, span, flag, border, userData); if ( Add(item) ) - return true; + return item; else { delete item; - return false; + return NULL; } } -bool wxGridBagSizer::Add( wxGBSizerItem *item ) +wxSizerItem* wxGridBagSizer::Add( wxGBSizerItem *item ) { - m_children.Append(item); - item->SetSizer(this); + wxCHECK_MSG( !CheckForIntersection(item), NULL, + wxT("An item is already at that position") ); + m_children.Append(item); + item->SetGBSizer(this); if ( item->GetWindow() ) item->GetWindow()->SetContainingSizer( this ); - return true; + // extend the number of rows/columns of the underlying wxFlexGridSizer if + // necessary + int row, col; + item->GetEndPos(row, col); + row++; + col++; + + if ( row > GetRows() ) + SetRows(row); + if ( col > GetCols() ) + SetCols(col); + + return item; } //--------------------------------------------------------------------------- +wxSize wxGridBagSizer::GetCellSize(int row, int col) const +{ + wxCHECK_MSG( (row < m_rows) && (col < m_cols), + wxDefaultSize, + wxT("Invalid cell.")); + return wxSize( m_colWidths[col], m_rowHeights[row] ); +} + + wxGBPosition wxGridBagSizer::GetItemPosition(wxWindow *window) { wxGBPosition badpos(-1,-1); @@ -260,8 +277,8 @@ wxGBPosition wxGridBagSizer::GetItemPosition(size_t index) { wxGBPosition badpos(-1,-1); wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badpos, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxCHECK_MSG( node, badpos, wxT("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); return item->GetPos(); } @@ -286,8 +303,8 @@ bool wxGridBagSizer::SetItemPosition(wxSizer *sizer, const wxGBPosition& pos) bool wxGridBagSizer::SetItemPosition(size_t index, const wxGBPosition& pos) { wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxCHECK_MSG( node, false, wxT("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); return item->SetPos(pos); } @@ -297,7 +314,7 @@ wxGBSpan wxGridBagSizer::GetItemSpan(wxWindow *window) { wxGBSpan badspan(-1,-1); wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + wxCHECK_MSG( item, badspan, wxT("Failed to find item.") ); return item->GetSpan(); } @@ -306,7 +323,7 @@ wxGBSpan wxGridBagSizer::GetItemSpan(wxSizer *sizer) { wxGBSpan badspan(-1,-1); wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + wxCHECK_MSG( item, badspan, wxT("Failed to find item.") ); return item->GetSpan(); } @@ -315,8 +332,8 @@ wxGBSpan wxGridBagSizer::GetItemSpan(size_t index) { wxGBSpan badspan(-1,-1); wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badspan, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxCHECK_MSG( node, badspan, wxT("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); return item->GetSpan(); } @@ -341,8 +358,8 @@ bool wxGridBagSizer::SetItemSpan(wxSizer *sizer, const wxGBSpan& span) bool wxGridBagSizer::SetItemSpan(size_t index, const wxGBSpan& span) { wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxCHECK_MSG( node, false, wxT("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); return item->SetSpan(span); } @@ -395,6 +412,24 @@ wxGBSizerItem* wxGridBagSizer::FindItemAtPosition(const wxGBPosition& pos) +wxGBSizerItem* wxGridBagSizer::FindItemAtPoint(const wxPoint& pt) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxRect rect(item->GetPosition(), item->GetSize()); + rect.Inflate(m_hgap, m_vgap); + if ( rect.Contains(pt) ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) { wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); @@ -418,7 +453,7 @@ wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) wxSize wxGridBagSizer::CalcMin() { int idx; - + if (m_children.GetCount() == 0) return m_emptyCellSize; @@ -432,14 +467,14 @@ wxSize wxGridBagSizer::CalcMin() if ( item->IsShown() ) { int row, col, endrow, endcol; - + item->GetPos(row, col); item->GetEndPos(endrow, endcol); // fill heights and widths upto this item if needed - while ( m_rowHeights.GetCount() <= (size_t)endrow ) + while ( (int)m_rowHeights.GetCount() <= endrow ) m_rowHeights.Add(m_emptyCellSize.GetHeight()); - while ( m_colWidths.GetCount() <= (size_t)endcol ) + while ( (int)m_colWidths.GetCount() <= endcol ) m_colWidths.Add(m_emptyCellSize.GetWidth()); // See if this item increases the size of its row(s) or col(s) @@ -452,20 +487,22 @@ wxSize wxGridBagSizer::CalcMin() node = node->GetNext(); } + AdjustForOverflow(); AdjustForFlexDirection(); // Now traverse the heights and widths arrays calcing the totals, including gaps int width = 0; - int ncols = m_colWidths.GetCount(); - for (idx=0; idx < ncols; idx++) - width += m_colWidths[idx] + ( idx == ncols-1 ? 0 : m_hgap ); + m_cols = m_colWidths.GetCount(); + for (idx=0; idx < m_cols; idx++) + width += m_colWidths[idx] + ( idx == m_cols-1 ? 0 : m_hgap ); int height = 0; - int nrows = m_rowHeights.GetCount(); - for (idx=0; idx < nrows; idx++) - height += m_rowHeights[idx] + ( idx == nrows-1 ? 0 : m_vgap ); + m_rows = m_rowHeights.GetCount(); + for (idx=0; idx < m_rows; idx++) + height += m_rowHeights[idx] + ( idx == m_rows-1 ? 0 : m_vgap ); - return wxSize(width, height); + m_calculatedMinSize = wxSize(width, height); + return m_calculatedMinSize; } @@ -475,23 +512,20 @@ void wxGridBagSizer::RecalcSizes() if (m_children.GetCount() == 0) return; - // Calculates minsize and populates m_rowHeights and m_colWidths - wxSize minsz( CalcMin() ); - wxPoint pt( GetPosition() ); wxSize sz( GetSize() ); - - int nrows = m_rowHeights.GetCount(); - int ncols = m_colWidths.GetCount(); + + m_rows = m_rowHeights.GetCount(); + m_cols = m_colWidths.GetCount(); int idx, width, height; - AdjustForGrowables(sz, minsz, nrows, ncols); + AdjustForGrowables(sz); // Find the start positions on the window of the rows and columns wxArrayInt rowpos; - rowpos.Add(0, nrows); + rowpos.Add(0, m_rows); int y = pt.y; - for (idx=0; idx < nrows; idx++) + for (idx=0; idx < m_rows; idx++) { height = m_rowHeights[idx] + m_vgap; rowpos[idx] = y; @@ -499,9 +533,9 @@ void wxGridBagSizer::RecalcSizes() } wxArrayInt colpos; - colpos.Add(0, ncols); + colpos.Add(0, m_cols); int x = pt.x; - for (idx=0; idx < ncols; idx++) + for (idx=0; idx < m_cols; idx++) { width = m_colWidths[idx] + m_hgap; colpos[idx] = x; @@ -515,24 +549,122 @@ void wxGridBagSizer::RecalcSizes() { int row, col, endrow, endcol; wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - item->GetPos(row, col); - item->GetEndPos(endrow, endcol); - - height = 0; - for(idx=row; idx <= endrow; idx++) - height += m_rowHeights[idx] + m_vgap; - - width = 0; - for (idx=col; idx <= endcol; idx++) - width += m_colWidths[idx] + m_hgap; - - SetItemBounds(item, colpos[col], rowpos[row], width, height); + + if ( item->IsShown() ) + { + item->GetPos(row, col); + item->GetEndPos(endrow, endcol); + + height = 0; + for(idx=row; idx <= endrow; idx++) + height += m_rowHeights[idx]; + height += (endrow - row) * m_vgap; // add a vgap for every row spanned + + width = 0; + for (idx=col; idx <= endcol; idx++) + width += m_colWidths[idx]; + width += (endcol - col) * m_hgap; // add a hgap for every col spanned + + SetItemBounds(item, colpos[col], rowpos[row], width, height); + } node = node->GetNext(); - } + } } +// Sometimes CalcMin can result in some rows or cols having too much space in +// them because as it traverses the items it makes some assumptions when +// items span to other cells. But those assumptions can become invalid later +// on when other items are fitted into the same rows or columns that the +// spanning item occupies. This method tries to find those situations and +// fixes them. +void wxGridBagSizer::AdjustForOverflow() +{ + int row, col; + + for (row=0; row<(int)m_rowHeights.GetCount(); row++) + { + int rowExtra=INT_MAX; + int rowHeight = m_rowHeights[row]; + for (col=0; col<(int)m_colWidths.GetCount(); col++) + { + wxGBPosition pos(row,col); + wxGBSizerItem* item = FindItemAtPosition(pos); + if ( !item || !item->IsShown() ) + continue; + + int endrow, endcol; + item->GetEndPos(endrow, endcol); + + // If the item starts in this position and doesn't span rows, then + // just look at the whole item height + if ( item->GetPos() == pos && endrow == row ) + { + int itemHeight = item->CalcMin().GetHeight(); + rowExtra = wxMin(rowExtra, rowHeight - itemHeight); + continue; + } + + // Otherwise, only look at spanning items if they end on this row + if ( endrow == row ) + { + // first deduct the portions of the item that are on prior rows + int itemHeight = item->CalcMin().GetHeight(); + for (int r=item->GetPos().GetRow(); rIsShown() ) + continue; + + int endrow, endcol; + item->GetEndPos(endrow, endcol); + + if ( item->GetPos() == pos && endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + colExtra = wxMin(colExtra, colWidth - itemWidth); + continue; + } + + if ( endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + for (int c=item->GetPos().GetCol(); cIntersects(pos, span) ) return true; @@ -584,19 +716,19 @@ wxGBPosition wxGridBagSizer::FindEmptyCell() // we'll try to make them automatically select a location for the item // anyway. -void wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) { - Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); + return Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); } -void wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) { - Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); + return Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); } -void wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) +wxSizerItem* wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) { - Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); + return Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); } @@ -605,33 +737,60 @@ void wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxOb // this class and should not be used. Their implementation in this class // simply fails. -void wxGridBagSizer::Add( wxSizerItem *item ) -{ wxFAIL_MSG(wxT("Invalid Add form called.")); } +wxSizerItem* wxGridBagSizer::Add( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Invalid Add form called.")); + return NULL; +} -void wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Prepend( wxSizerItem * ) -{ wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Prepend( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) -{ wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return NULL; +} -void wxGridBagSizer::Insert( size_t, wxSizerItem * ) -{ wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); } +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return NULL; +} //---------------------------------------------------------------------------