+//---------------------------------------------------------------------------
+// wxWrapSizer
+//---------------------------------------------------------------------------
+
+#define wxDEFAULT_PROPORTION_LAST 1000000
+
+// User data to hold old proportion for last item on line
+// (which might be extended)
+struct wxPropHolder : public wxObject
+{
+ wxPropHolder( ) : m_item(0), m_propOld(0) { }
+ void Init( wxSizerItem *item, int propOld ) { m_item=item; m_propOld=propOld; }
+
+ wxSizerItem *m_item;
+ int m_propOld;
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxWrapSizer, wxBoxSizer);
+
+wxWrapSizer::wxWrapSizer( int orient, int flags )
+ : wxBoxSizer(orient),
+ m_prim_size_last( -1 ),
+ m_rows(orient^wxBOTH),
+ m_flags(flags)
+{
+}
+
+wxWrapSizer::~wxWrapSizer()
+{
+ // Have to clear grand child items so that they're not deleted twice
+ for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- )
+ {
+ wxSizer *psz = m_rows.GetItem((size_t)ix)->GetSizer();
+ wxSizerItemList &sl = psz->GetChildren();
+ while( sl.GetLast() )
+ sl.Erase( sl.GetLast() );
+ }
+}
+
+
+bool wxWrapSizer::InformFirstDirection( int direction, int size, int WXUNUSED(availableOtherDir) )
+{
+ if( !direction )
+ {
+ // Better to keep value, then CalcMin will work better
+ //m_prim_size_last = -1;
+ return false;
+ }
+ if( direction==m_orient )
+ {
+ // The direction is same as our primary, so we can make use of it
+ m_prim_size_last = size;
+ return true;
+ }
+ else
+ return false;
+}
+
+
+void wxWrapSizer::AdjustPropLastItem(wxSizer *psz, wxSizerItem *itemLast)
+{
+ wxSizerItem *psi = m_rows.GetItem(psz);
+ wxASSERT(psi);
+ wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
+ if ( !pph )
+ psi->SetUserData( pph=new wxPropHolder );
+
+ pph->Init( itemLast, itemLast->GetProportion() );
+ itemLast->SetProportion( wxDEFAULT_PROPORTION_LAST );
+}
+
+void wxWrapSizer::RecalcSizes()
+{
+ wxASSERT( m_orient&wxBOTH );
+ if (m_children.GetCount() == 0)
+ return;
+
+ // What we do here is to put our items into child box sizers,
+ // as many of them as we have lines.
+
+ // Empty all items in all rows in owned sizer.
+ // We have to access the list directly, since we don't want to
+ // destroy the wxSizerItems.
+ for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- ){
+ wxSizerItem *psi = m_rows.GetItem( (size_t)ix );
+
+ // Restore proportion for last item on line (if item has not been deleted)
+ wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
+ if( pph && GetChildren().Find(pph->m_item) )
+ pph->m_item->SetProportion(pph->m_propOld);
+
+ wxSizer *psz = psi->GetSizer();
+ wxASSERT( psz );
+ wxSizerItemList &sl = psz->GetChildren();
+ while( sl.GetLast() )
+ sl.Erase( sl.GetLast() );
+ }
+
+ int lineSumMajor = 0;
+ int majorSize = GetSizeInMajorDir(m_size);
+
+ // Make sure we have at least one child sizer
+ m_n_line = 1;
+ if( !m_rows.GetChildren().GetCount() )
+ m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
+
+ // The sizer where to insert items in
+ wxSizer *psz = m_rows.GetItem((size_t)0)->GetSizer();
+ wxASSERT( psz );
+
+ // Now put our child items into child sizers instead
+ wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
+ wxSizerItem *item = NULL, *itemLast=NULL;
+ while (node)
+ {
+ item = node->GetData();
+ if ( item->IsShown() )
+ {
+ wxSize minSz = item->GetMinSize();
+ int minSzMajor = GetSizeInMajorDir(minSz);
+
+ // More space on this line?
+ if( !lineSumMajor || lineSumMajor+minSzMajor<=majorSize )
+ {
+ lineSumMajor += minSzMajor;
+ }
+ else
+ {
+ lineSumMajor = minSzMajor;
+ // Get a new empty sizer to insert into
+ if( (int)m_rows.GetChildren().GetCount()<=m_n_line )
+ m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
+
+ // If we have extend-last-on-each-line mode, then do so now
+ // Note: We must store old proportion value then.
+ if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
+ AdjustPropLastItem(psz,itemLast);
+
+ // The sizer where to insert items in
+ psz = m_rows.GetItem(m_n_line++)->GetSizer();
+ }
+ itemLast = item;
+ psz->Add( item );
+ // If item is a window, it now has a pointer to the child sizer,
+ // which is wrong. Set it to point to us.
+ if( item->GetWindow() )
+ item->GetWindow()->SetContainingSizer( this );
+ }
+ node = node->GetNext();
+ }
+
+ // If we have extend-last-on-each-line mode, then do so now
+ if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
+ AdjustPropLastItem(psz,itemLast);
+
+ // If we have more sizers than lines, remove them
+ while( (int)m_rows.GetChildren().GetCount()>m_n_line )
+ m_rows.Remove( m_n_line );
+
+ // Now do layout on row sizer
+ m_rows.SetDimension( m_position.x, m_position.y, m_size.x, m_size.y );
+
+ // Remember this to next time (will be overridden by InformFirstDirection if used)
+ m_prim_size_last = GetSizeInMajorDir(m_size);
+}
+
+
+wxSize wxWrapSizer::CalcMin()
+{
+ if (m_children.GetCount() == 0)
+ return wxSize();
+
+ // Algorithm for calculating min size: (assuming horizontal orientation)
+ // X: Max width of all members
+ // Y: Based on last X, calculate how many lines needed
+ // First time around, assume all items fits on one line
+
+ int maxMajor = 0;
+ int minorSum = 0;
+ int lineMaxMinor = 0;
+ int lineSumMajor = 0;
+ m_n_line = 0;
+
+ // precalc item minsizes and fit on lines (preliminary)
+ wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxSizerItem *item = node->GetData();
+ if ( item->IsShown() )
+ {
+ wxSize minSz = item->CalcMin();
+ int szMajor = GetSizeInMajorDir(minSz);
+ int szMinor = GetSizeInMinorDir(minSz);
+ if( szMajor>maxMajor ) maxMajor = szMajor;
+ // More space on this line?
+ if( m_prim_size_last<0 || !lineSumMajor ||
+ lineSumMajor+szMajor<=m_prim_size_last )
+ {
+ lineSumMajor += szMajor;
+ if( szMinor>lineMaxMinor )
+ lineMaxMinor = szMinor;
+ }
+ else
+ {
+ minorSum += lineMaxMinor; // Add height of highest item on last line
+ m_n_line++;
+ lineMaxMinor = szMinor;
+ lineSumMajor = szMajor;
+ }
+ }
+ node = node->GetNext();
+ }
+ minorSum += lineMaxMinor; // Add height of highest item on last line
+
+ m_minSize = SizeFromMajorMinor(maxMajor, minorSum);
+ return m_minSize;
+}
+