boxsizer.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Name: tests/sizers/boxsizer.cpp
  3. // Purpose: Unit tests for wxBoxSizer
  4. // Author: Vadim Zeitlin
  5. // Created: 2010-03-06
  6. // Copyright: (c) 2010 Vadim Zeitlin <vadim@wxwidgets.org>
  7. ///////////////////////////////////////////////////////////////////////////////
  8. // ----------------------------------------------------------------------------
  9. // headers
  10. // ----------------------------------------------------------------------------
  11. #include "testprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. #ifndef WX_PRECOMP
  16. #include "wx/app.h"
  17. #include "wx/sizer.h"
  18. #include "wx/listbox.h"
  19. #endif // WX_PRECOMP
  20. #include "asserthelper.h"
  21. // ----------------------------------------------------------------------------
  22. // test class
  23. // ----------------------------------------------------------------------------
  24. class BoxSizerTestCase : public CppUnit::TestCase
  25. {
  26. public:
  27. BoxSizerTestCase() { }
  28. virtual void setUp();
  29. virtual void tearDown();
  30. private:
  31. CPPUNIT_TEST_SUITE( BoxSizerTestCase );
  32. CPPUNIT_TEST( Size1 );
  33. CPPUNIT_TEST( Size3 );
  34. CPPUNIT_TEST( CalcMin );
  35. CPPUNIT_TEST( BestSizeRespectsMaxSize );
  36. CPPUNIT_TEST( RecalcSizesRespectsMaxSize1 );
  37. CPPUNIT_TEST( RecalcSizesRespectsMaxSize2 );
  38. CPPUNIT_TEST_SUITE_END();
  39. void Size1();
  40. void Size3();
  41. void CalcMin();
  42. void BestSizeRespectsMaxSize();
  43. void RecalcSizesRespectsMaxSize1();
  44. void RecalcSizesRespectsMaxSize2();
  45. wxWindow *m_win;
  46. wxSizer *m_sizer;
  47. DECLARE_NO_COPY_CLASS(BoxSizerTestCase)
  48. };
  49. // register in the unnamed registry so that these tests are run by default
  50. CPPUNIT_TEST_SUITE_REGISTRATION( BoxSizerTestCase );
  51. // also include in its own registry so that these tests can be run alone
  52. CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( BoxSizerTestCase, "BoxSizerTestCase" );
  53. // ----------------------------------------------------------------------------
  54. // test initialization
  55. // ----------------------------------------------------------------------------
  56. void BoxSizerTestCase::setUp()
  57. {
  58. m_win = new wxWindow(wxTheApp->GetTopWindow(), wxID_ANY);
  59. m_win->SetClientSize(127, 35);
  60. m_sizer = new wxBoxSizer(wxHORIZONTAL);
  61. m_win->SetSizer(m_sizer);
  62. }
  63. void BoxSizerTestCase::tearDown()
  64. {
  65. delete m_win;
  66. m_win = NULL;
  67. m_sizer = NULL;
  68. }
  69. // ----------------------------------------------------------------------------
  70. // tests themselves
  71. // ----------------------------------------------------------------------------
  72. void BoxSizerTestCase::Size1()
  73. {
  74. const wxSize sizeTotal = m_win->GetClientSize();
  75. const wxSize sizeChild = sizeTotal / 2;
  76. wxWindow * const
  77. child = new wxWindow(m_win, wxID_ANY, wxDefaultPosition, sizeChild);
  78. m_sizer->Add(child);
  79. m_win->Layout();
  80. CPPUNIT_ASSERT_EQUAL( sizeChild, child->GetSize() );
  81. m_sizer->Clear();
  82. m_sizer->Add(child, wxSizerFlags(1));
  83. m_win->Layout();
  84. CPPUNIT_ASSERT_EQUAL( wxSize(sizeTotal.x, sizeChild.y), child->GetSize() );
  85. m_sizer->Clear();
  86. m_sizer->Add(child, wxSizerFlags(1).Expand());
  87. m_win->Layout();
  88. CPPUNIT_ASSERT_EQUAL( sizeTotal, child->GetSize() );
  89. m_sizer->Clear();
  90. m_sizer->Add(child, wxSizerFlags());
  91. m_sizer->SetItemMinSize(child, sizeTotal*2);
  92. m_win->Layout();
  93. CPPUNIT_ASSERT_EQUAL( sizeTotal, child->GetSize() );
  94. m_sizer->Clear();
  95. m_sizer->Add(child, wxSizerFlags().Expand());
  96. m_sizer->SetItemMinSize(child, sizeTotal*2);
  97. m_win->Layout();
  98. CPPUNIT_ASSERT_EQUAL( sizeTotal, child->GetSize() );
  99. }
  100. void BoxSizerTestCase::Size3()
  101. {
  102. // check that various combinations of minimal sizes and proportions work as
  103. // expected for different window sizes
  104. static const struct LayoutTestData
  105. {
  106. // proportions of the elements
  107. int prop[3];
  108. // minimal sizes of the elements in the sizer direction
  109. int minsize[3];
  110. // total size and the expected sizes of the elements
  111. int x,
  112. sizes[3];
  113. // if true, don't try the permutations of our test data
  114. bool dontPermute;
  115. // Add the given window to the sizer with the corresponding parameters
  116. void AddToSizer(wxSizer *sizer, wxWindow *win, int n) const
  117. {
  118. sizer->Add(win, wxSizerFlags(prop[n]));
  119. sizer->SetItemMinSize(win, wxSize(minsize[n], -1));
  120. }
  121. } layoutTestData[] =
  122. {
  123. // some really simple cases (no need to permute those, they're
  124. // symmetrical anyhow)
  125. { { 1, 1, 1, }, { 50, 50, 50, }, 150, { 50, 50, 50, }, true },
  126. { { 2, 2, 2, }, { 50, 50, 50, }, 600, { 200, 200, 200, }, true },
  127. // items with different proportions and min sizes when there is enough
  128. // space to lay them out
  129. { { 1, 2, 3, }, { 0, 0, 0, }, 600, { 100, 200, 300, } },
  130. { { 1, 2, 3, }, { 100, 100, 100, }, 600, { 100, 200, 300, } },
  131. { { 1, 2, 3, }, { 100, 50, 50, }, 600, { 100, 200, 300, } },
  132. { { 0, 1, 1, }, { 200, 100, 100, }, 600, { 200, 200, 200, } },
  133. { { 0, 1, 2, }, { 300, 100, 100, }, 600, { 300, 100, 200, } },
  134. { { 0, 1, 1, }, { 100, 50, 50, }, 300, { 100, 100, 100, } },
  135. { { 0, 1, 2, }, { 100, 50, 50, }, 400, { 100, 100, 200, } },
  136. // cases when there is not enough space to lay out the items correctly
  137. // while still respecting their min sizes
  138. { { 0, 1, 1, }, { 100, 150, 50, }, 300, { 100, 150, 50, } },
  139. { { 1, 2, 3, }, { 100, 100, 100, }, 300, { 100, 100, 100, } },
  140. { { 1, 2, 3, }, { 100, 50, 50, }, 300, { 100, 80, 120, } },
  141. { { 1, 2, 3, }, { 100, 10, 10, }, 150, { 100, 20, 30, } },
  142. // cases when there is not enough space even for the min sizes (don't
  143. // permute in these cases as the layout does depend on the item order
  144. // because the first ones have priority)
  145. { { 1, 2, 3, }, { 100, 50, 50, }, 150, { 100, 50, 0, }, true },
  146. { { 1, 2, 3, }, { 100, 100, 100, }, 200, { 100, 100, 0, }, true },
  147. { { 1, 2, 3, }, { 100, 100, 100, }, 150, { 100, 50, 0, }, true },
  148. { { 1, 2, 3, }, { 100, 100, 100, }, 50, { 50, 0, 0, }, true },
  149. { { 1, 2, 3, }, { 100, 100, 100, }, 0, { 0, 0, 0, }, true },
  150. };
  151. wxWindow *child[3];
  152. child[0] = new wxWindow(m_win, wxID_ANY);
  153. child[1] = new wxWindow(m_win, wxID_ANY);
  154. child[2] = new wxWindow(m_win, wxID_ANY);
  155. for ( unsigned i = 0; i < WXSIZEOF(layoutTestData); i++ )
  156. {
  157. LayoutTestData ltd = layoutTestData[i];
  158. // the results shouldn't depend on the order of items except in the
  159. // case when there is not enough space for even the fixed width items
  160. // (in which case the first ones might get enough of it but not the
  161. // last ones) so test a couple of permutations of test data unless
  162. // specifically disabled for this test case
  163. for ( unsigned p = 0; p < 3; p++)
  164. {
  165. switch ( p )
  166. {
  167. case 0:
  168. // nothing to do, use original data
  169. break;
  170. case 1:
  171. // exchange first and last elements
  172. wxSwap(ltd.prop[0], ltd.prop[2]);
  173. wxSwap(ltd.minsize[0], ltd.minsize[2]);
  174. wxSwap(ltd.sizes[0], ltd.sizes[2]);
  175. break;
  176. case 2:
  177. // exchange the original third and second elements
  178. wxSwap(ltd.prop[0], ltd.prop[1]);
  179. wxSwap(ltd.minsize[0], ltd.minsize[1]);
  180. wxSwap(ltd.sizes[0], ltd.sizes[1]);
  181. break;
  182. }
  183. m_sizer->Clear();
  184. unsigned j;
  185. for ( j = 0; j < WXSIZEOF(child); j++ )
  186. ltd.AddToSizer(m_sizer, child[j], j);
  187. m_win->SetClientSize(ltd.x, -1);
  188. m_win->Layout();
  189. for ( j = 0; j < WXSIZEOF(child); j++ )
  190. {
  191. WX_ASSERT_EQUAL_MESSAGE
  192. (
  193. (
  194. "test %lu, permutation #%lu: wrong size for child #%d "
  195. "for total size %d",
  196. static_cast<unsigned long>(i),
  197. static_cast<unsigned long>(p),
  198. j,
  199. ltd.x
  200. ),
  201. ltd.sizes[j], child[j]->GetSize().x
  202. );
  203. }
  204. // don't try other permutations if explicitly disabled
  205. if ( ltd.dontPermute )
  206. break;
  207. }
  208. }
  209. }
  210. void BoxSizerTestCase::CalcMin()
  211. {
  212. static const unsigned NUM_TEST_ITEM = 3;
  213. static const struct CalcMinTestData
  214. {
  215. // proportions of the elements, if one of them is -1 it means to not
  216. // use this window at all in this test
  217. int prop[NUM_TEST_ITEM];
  218. // minimal sizes of the elements in the sizer direction
  219. int minsize[NUM_TEST_ITEM];
  220. // the expected minimal sizer size
  221. int total;
  222. } calcMinTestData[] =
  223. {
  224. { { 1, 1, -1 }, { 30, 50, 0 }, 100 },
  225. { { 1, 1, 0 }, { 30, 50, 20 }, 120 },
  226. { { 10, 10, -1 }, { 30, 50, 0 }, 100 },
  227. { { 1, 2, 2 }, { 50, 50, 80 }, 250 },
  228. { { 1, 2, 2 }, { 100, 50, 80 }, 500 },
  229. };
  230. unsigned n;
  231. wxWindow *child[NUM_TEST_ITEM];
  232. for ( n = 0; n < NUM_TEST_ITEM; n++ )
  233. child[n] = new wxWindow(m_win, wxID_ANY);
  234. for ( unsigned i = 0; i < WXSIZEOF(calcMinTestData); i++ )
  235. {
  236. m_sizer->Clear();
  237. const CalcMinTestData& cmtd = calcMinTestData[i];
  238. for ( n = 0; n < NUM_TEST_ITEM; n++ )
  239. {
  240. if ( cmtd.prop[n] != -1 )
  241. {
  242. child[n]->SetInitialSize(wxSize(cmtd.minsize[n], -1));
  243. m_sizer->Add(child[n], wxSizerFlags(cmtd.prop[n]));
  244. }
  245. }
  246. WX_ASSERT_EQUAL_MESSAGE
  247. (
  248. ("In test #%u", i),
  249. cmtd.total, m_sizer->CalcMin().x
  250. );
  251. }
  252. }
  253. void BoxSizerTestCase::BestSizeRespectsMaxSize()
  254. {
  255. m_sizer->Clear();
  256. const int maxWidth = 100;
  257. wxSizer* sizer = new wxBoxSizer(wxVERTICAL);
  258. wxListBox* listbox = new wxListBox(m_win, wxID_ANY);
  259. listbox->Append("some very very very very very very very very very very very long string");
  260. listbox->SetMaxSize(wxSize(maxWidth, -1));
  261. sizer->Add(listbox);
  262. m_sizer->Add(sizer);
  263. m_win->Layout();
  264. CPPUNIT_ASSERT_EQUAL(maxWidth, listbox->GetSize().GetWidth());
  265. }
  266. void BoxSizerTestCase::RecalcSizesRespectsMaxSize1()
  267. {
  268. m_sizer->Clear();
  269. const int maxWidth = 100;
  270. m_win->SetClientSize(300, 300);
  271. wxSizer* sizer1 = new wxBoxSizer(wxVERTICAL);
  272. m_sizer->Add(sizer1);
  273. wxListBox* listbox1 = new wxListBox(m_win, wxID_ANY);
  274. listbox1->Append("some very very very very very very very very very very very long string");
  275. sizer1->Add(listbox1);
  276. wxSizer* sizer2 = new wxBoxSizer(wxHORIZONTAL);
  277. sizer1->Add(sizer2, wxSizerFlags().Expand());
  278. wxListBox* listbox2 = new wxListBox(m_win, wxID_ANY);
  279. listbox2->Append("some string");
  280. listbox2->SetMaxSize(wxSize(100, -1));
  281. sizer2->Add(listbox2, wxSizerFlags().Proportion(1));
  282. m_win->Layout();
  283. CPPUNIT_ASSERT_EQUAL(maxWidth, listbox2->GetSize().GetWidth());
  284. }
  285. void BoxSizerTestCase::RecalcSizesRespectsMaxSize2()
  286. {
  287. m_sizer->Clear();
  288. m_win->SetClientSize(300, 300);
  289. wxSizer* sizer1 = new wxBoxSizer(wxVERTICAL);
  290. m_sizer->Add(sizer1, wxSizerFlags().Expand());
  291. wxWindow* child1 = new wxWindow(m_win, wxID_ANY);
  292. sizer1->Add(child1, wxSizerFlags().Proportion(1));
  293. wxWindow* child2 = new wxWindow(m_win, wxID_ANY);
  294. child2->SetMaxSize(wxSize(-1, 50));
  295. sizer1->Add(child2, wxSizerFlags().Proportion(1));
  296. wxWindow* child3 = new wxWindow(m_win, wxID_ANY);
  297. sizer1->Add(child3, wxSizerFlags().Proportion(1));
  298. m_win->Layout();
  299. CPPUNIT_ASSERT_EQUAL(125, child1->GetSize().GetHeight());
  300. CPPUNIT_ASSERT_EQUAL(50, child2->GetSize().GetHeight());
  301. CPPUNIT_ASSERT_EQUAL(125, child3->GetSize().GetHeight());
  302. }