diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index 31f2503850..badc6724ab 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -2300,7 +2300,12 @@ wxSize wxBoxSizer::CalcMin() m_totalProportion = 0; m_minSize = wxSize(0, 0); - // calculate the minimal sizes for all items and count sum of proportions + // The minimal size for the sizer should be big enough to allocate its + // element at least its minimal size but also, and this is the non trivial + // part, to respect the children proportion. To satisfy the latter + // condition we must find the greatest min-size-to-proportion ratio for all + // elements with non-zero proportion. + float maxMinSizeToProp = 0.; for ( wxSizerItemList::const_iterator i = m_children.begin(); i != m_children.end(); ++i ) @@ -2311,13 +2316,31 @@ wxSize wxBoxSizer::CalcMin() continue; const wxSize sizeMinThis = item->CalcMin(); - SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis); + if ( const int propThis = item->GetProportion() ) + { + float minSizeToProp = GetSizeInMajorDir(sizeMinThis); + minSizeToProp /= propThis; + + if ( minSizeToProp > maxMinSizeToProp ) + maxMinSizeToProp = minSizeToProp; + + m_totalProportion += item->GetProportion(); + } + else // fixed size item + { + // Just account for its size directly + SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis); + } + + // In the transversal direction we just need to find the maximum. if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) ) SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis); - - m_totalProportion += item->GetProportion(); } + // Using the max ratio ensures that the min size is big enough for all + // items to have their min size and satisfy the proportions among them. + SizeInMajorDir(m_minSize) += maxMinSizeToProp*m_totalProportion; + return m_minSize; } diff --git a/tests/sizers/boxsizer.cpp b/tests/sizers/boxsizer.cpp index 558f15883b..ca203d2379 100644 --- a/tests/sizers/boxsizer.cpp +++ b/tests/sizers/boxsizer.cpp @@ -43,10 +43,12 @@ private: CPPUNIT_TEST_SUITE( BoxSizerTestCase ); CPPUNIT_TEST( Size1 ); CPPUNIT_TEST( Size3 ); + CPPUNIT_TEST( CalcMin ); CPPUNIT_TEST_SUITE_END(); void Size1(); void Size3(); + void CalcMin(); wxWindow *m_win; wxSizer *m_sizer; @@ -248,3 +250,54 @@ void BoxSizerTestCase::Size3() } } } + +void BoxSizerTestCase::CalcMin() +{ + static const unsigned NUM_TEST_ITEM = 3; + + static const struct CalcMinTestData + { + // proportions of the elements, if one of them is -1 it means to not + // use this window at all in this test + int prop[NUM_TEST_ITEM]; + + // minimal sizes of the elements in the sizer direction + int minsize[NUM_TEST_ITEM]; + + // the expected minimal sizer size + int total; + } calcMinTestData[] = + { + { { 1, 1, -1 }, { 30, 50, 0 }, 100 }, + { { 1, 1, 0 }, { 30, 50, 20 }, 120 }, + { { 10, 10, -1 }, { 30, 50, 0 }, 100 }, + { { 1, 2, 2 }, { 50, 50, 80 }, 250 }, + { { 1, 2, 2 }, { 100, 50, 80 }, 500 }, + }; + + unsigned n; + wxWindow *child[NUM_TEST_ITEM]; + for ( n = 0; n < NUM_TEST_ITEM; n++ ) + child[n] = new wxWindow(m_win, wxID_ANY); + + for ( unsigned i = 0; i < WXSIZEOF(calcMinTestData); i++ ) + { + m_sizer->Clear(); + + const CalcMinTestData& cmtd = calcMinTestData[i]; + for ( n = 0; n < NUM_TEST_ITEM; n++ ) + { + if ( cmtd.prop[n] != -1 ) + { + child[n]->SetInitialSize(wxSize(cmtd.minsize[n], -1)); + m_sizer->Add(child[n], wxSizerFlags(cmtd.prop[n])); + } + } + + WX_ASSERT_EQUAL_MESSAGE + ( + ("In test #%u", i), + cmtd.total, m_sizer->CalcMin().x + ); + } +}