home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / sizer.cpp < prev    next >
C/C++ Source or Header  |  2002-08-30  |  33KB  |  1,244 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        sizer.cpp
  3. // Purpose:     provide new wxSizer class for layout
  4. // Author:      Robert Roebling and Robin Dunn
  5. // Modified by: Ron Lee
  6. // Created:
  7. // RCS-ID:      $Id: sizer.cpp,v 1.46 2002/08/29 21:48:32 VZ Exp $
  8. // Copyright:   (c) Robin Dunn, Dirk Holtwick and Robert Roebling
  9. // Licence:     wxWindows licence
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. #ifdef __GNUG__
  13. #pragma implementation "sizer.h"
  14. #endif
  15.  
  16. // For compilers that support precompilation, includes "wx.h".
  17. #include "wx/wxprec.h"
  18.  
  19. #ifdef __BORLANDC__
  20.     #pragma hdrstop
  21. #endif
  22.  
  23. #include "wx/sizer.h"
  24. #include "wx/utils.h"
  25. #include "wx/statbox.h"
  26. #include "wx/notebook.h"
  27.  
  28. //---------------------------------------------------------------------------
  29.  
  30. IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject)
  31. IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject)
  32. IMPLEMENT_ABSTRACT_CLASS(wxGridSizer, wxSizer)
  33. IMPLEMENT_ABSTRACT_CLASS(wxFlexGridSizer, wxGridSizer)
  34. IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer)
  35. #if wxUSE_STATBOX
  36. IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer)
  37. #endif
  38. #if wxUSE_NOTEBOOK
  39. IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer)
  40. #endif
  41.  
  42. //---------------------------------------------------------------------------
  43. // wxSizerItem
  44. //---------------------------------------------------------------------------
  45.  
  46. wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
  47. {
  48.     m_window = (wxWindow *) NULL;
  49.     m_sizer = (wxSizer *) NULL;
  50.     m_option = option;
  51.     m_border = border;
  52.     m_flag = flag;
  53.     m_userData = userData;
  54.  
  55.     // minimal size is the initial size
  56.     m_minSize.x = width;
  57.     m_minSize.y = height;
  58.  
  59.     SetRatio(width, height);
  60.  
  61.     // size is set directly
  62.     m_size = m_minSize;
  63. }
  64.  
  65. wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
  66. {
  67.     m_window = window;
  68.     m_sizer = (wxSizer *) NULL;
  69.     m_option = option;
  70.     m_border = border;
  71.     m_flag = flag;
  72.     m_userData = userData;
  73.  
  74.     // minimal size is the initial size
  75.     m_minSize = window->GetSize();
  76.  
  77.     // aspect ratio calculated from initial size
  78.     SetRatio(m_minSize);
  79.  
  80.     // size is calculated later
  81.     // m_size = ...
  82. }
  83.  
  84. wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
  85. {
  86.     m_window = (wxWindow *) NULL;
  87.     m_sizer = sizer;
  88.     m_option = option;
  89.     m_border = border;
  90.     m_flag = flag;
  91.     m_userData = userData;
  92.  
  93.     // minimal size is calculated later
  94.     // m_minSize = ...
  95.     m_ratio = 0;
  96.  
  97.     // size is calculated later
  98.     // m_size = ...
  99. }
  100.  
  101. wxSizerItem::~wxSizerItem()
  102. {
  103.     if (m_userData)
  104.         delete m_userData;
  105.     if (m_sizer)
  106.         delete m_sizer;
  107. }
  108.  
  109.  
  110. wxSize wxSizerItem::GetSize()
  111. {
  112.     wxSize ret;
  113.     if (IsSizer())
  114.         ret = m_sizer->GetSize();
  115.     else
  116.     if (IsWindow())
  117.         ret = m_window->GetSize();
  118.     else ret = m_size;
  119.  
  120.     if (m_flag & wxWEST)
  121.         ret.x += m_border;
  122.     if (m_flag & wxEAST)
  123.         ret.x += m_border;
  124.     if (m_flag & wxNORTH)
  125.         ret.y += m_border;
  126.     if (m_flag & wxSOUTH)
  127.         ret.y += m_border;
  128.  
  129.     return ret;
  130. }
  131.  
  132. wxSize wxSizerItem::CalcMin()
  133. {
  134.     wxSize ret;
  135.     if (IsSizer())
  136.     {
  137.         ret = m_sizer->GetMinSize();
  138.  
  139.         // if we have to preserve aspect ratio _AND_ this is
  140.         // the first-time calculation, consider ret to be initial size
  141.         if ((m_flag & wxSHAPED) && !m_ratio)
  142.             SetRatio(ret);
  143.     }
  144.     else
  145.     {
  146.         if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
  147.         {
  148.             // check if the best (minimal, in fact) window size hadn't changed
  149.             // by chance: this may happen for, e.g. static text if its label
  150.             // changed
  151.             wxSize size = m_window->GetBestSize();
  152.             if ( size.x > m_minSize.x )
  153.                 m_minSize.x = size.x;
  154.             if ( size.y > m_minSize.y )
  155.                 m_minSize.y = size.y;
  156.         }
  157.  
  158.         ret = m_minSize;
  159.     }
  160.  
  161.     if (m_flag & wxWEST)
  162.         ret.x += m_border;
  163.     if (m_flag & wxEAST)
  164.         ret.x += m_border;
  165.     if (m_flag & wxNORTH)
  166.         ret.y += m_border;
  167.     if (m_flag & wxSOUTH)
  168.         ret.y += m_border;
  169.  
  170.     return ret;
  171. }
  172.  
  173. void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
  174. {
  175.     if (m_flag & wxSHAPED)
  176.     {
  177.         // adjust aspect ratio
  178.         int rwidth = (int) (size.y * m_ratio);
  179.         if (rwidth > size.x)
  180.         {
  181.             // fit horizontally
  182.             int rheight = (int) (size.x / m_ratio);
  183.             // add vertical space
  184.             if (m_flag & wxALIGN_CENTER_VERTICAL)
  185.                 pos.y += (size.y - rheight) / 2;
  186.             else if (m_flag & wxALIGN_BOTTOM)
  187.                 pos.y += (size.y - rheight);
  188.             // use reduced dimensions
  189.             size.y =rheight;
  190.         }
  191.         else if (rwidth < size.x)
  192.         {
  193.             // add horizontal space
  194.             if (m_flag & wxALIGN_CENTER_HORIZONTAL)
  195.                 pos.x += (size.x - rwidth) / 2;
  196.             else if (m_flag & wxALIGN_RIGHT)
  197.                 pos.x += (size.x - rwidth);
  198.             size.x = rwidth;
  199.         }
  200.     }
  201.  
  202.     // This is what GetPosition() returns. Since we calculate
  203.     // borders afterwards, GetPosition() will be the left/top
  204.     // corner of the surrounding border.
  205.     m_pos = pos;
  206.  
  207.     if (m_flag & wxWEST)
  208.     {
  209.         pos.x += m_border;
  210.         size.x -= m_border;
  211.     }
  212.     if (m_flag & wxEAST)
  213.     {
  214.         size.x -= m_border;
  215.     }
  216.     if (m_flag & wxNORTH)
  217.     {
  218.         pos.y += m_border;
  219.         size.y -= m_border;
  220.     }
  221.     if (m_flag & wxSOUTH)
  222.     {
  223.         size.y -= m_border;
  224.     }
  225.  
  226.     if (IsSizer())
  227.         m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
  228.  
  229.     if (IsWindow())
  230.         m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
  231.  
  232.     m_size = size;
  233. }
  234.  
  235. void wxSizerItem::DeleteWindows()
  236. {
  237.     if (m_window)
  238.          m_window->Destroy();
  239.  
  240.     if (m_sizer)
  241.         m_sizer->DeleteWindows();
  242. }
  243.  
  244. bool wxSizerItem::IsWindow()
  245. {
  246.     return (m_window != NULL);
  247. }
  248.  
  249. bool wxSizerItem::IsSizer()
  250. {
  251.     return (m_sizer != NULL);
  252. }
  253.  
  254. bool wxSizerItem::IsSpacer()
  255. {
  256.     return (m_window == NULL) && (m_sizer == NULL);
  257. }
  258.  
  259. //---------------------------------------------------------------------------
  260. // wxSizer
  261. //---------------------------------------------------------------------------
  262.  
  263. wxSizer::wxSizer()
  264. {
  265.     m_children.DeleteContents( TRUE );
  266.     m_minSize.x = 0;
  267.     m_minSize.y = 0;
  268. }
  269.  
  270. wxSizer::~wxSizer()
  271. {
  272.     Clear();
  273. }
  274.  
  275. void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
  276. {
  277.     m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
  278.     window->SetContainingSizer(this);
  279. }
  280.  
  281. void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
  282. {
  283.     m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
  284. }
  285.  
  286. void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
  287. {
  288.     m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
  289. }
  290.  
  291. void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
  292. {
  293.     m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
  294.     window->SetContainingSizer(this);
  295. }
  296.  
  297. void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
  298. {
  299.     m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
  300. }
  301.  
  302. void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
  303. {
  304.     m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
  305. }
  306.  
  307. void wxSizer::Insert( int before, wxWindow *window, int option, int flag, int border, wxObject* userData )
  308. {
  309.     m_children.Insert( before, new wxSizerItem( window, option, flag, border, userData ) );
  310.     window->SetContainingSizer(this);
  311. }
  312.  
  313. void wxSizer::Insert( int before, wxSizer *sizer, int option, int flag, int border, wxObject* userData )
  314. {
  315.     m_children.Insert( before, new wxSizerItem( sizer, option, flag, border, userData ) );
  316. }
  317.  
  318. void wxSizer::Insert( int before, int width, int height, int option, int flag, int border, wxObject* userData )
  319. {
  320.     m_children.Insert( before, new wxSizerItem( width, height, option, flag, border, userData ) );
  321. }
  322.  
  323. bool wxSizer::Remove( wxWindow *window )
  324. {
  325.     wxASSERT( window );
  326.  
  327.     wxNode *node = m_children.First();
  328.     while (node)
  329.     {
  330.         wxSizerItem *item = (wxSizerItem*)node->Data();
  331.         if (item->GetWindow() == window)
  332.         {
  333.             item->GetWindow()->SetContainingSizer(NULL);
  334.             m_children.DeleteNode( node );
  335.             return TRUE;
  336.         }
  337.         node = node->Next();
  338.     }
  339.  
  340.     return FALSE;
  341. }
  342.  
  343. bool wxSizer::Remove( wxSizer *sizer )
  344. {
  345.     wxASSERT( sizer );
  346.  
  347.     wxNode *node = m_children.First();
  348.     while (node)
  349.     {
  350.         wxSizerItem *item = (wxSizerItem*)node->Data();
  351.         if (item->GetSizer() == sizer)
  352.         {
  353.             m_children.DeleteNode( node );
  354.             return TRUE;
  355.         }
  356.         node = node->Next();
  357.     }
  358.  
  359.     return FALSE;
  360. }
  361.  
  362. bool wxSizer::Remove( int pos )
  363. {
  364.     wxNode *node = m_children.Nth( pos );
  365.     if (!node) return FALSE;
  366.  
  367.     m_children.DeleteNode( node );
  368.  
  369.     return TRUE;
  370. }
  371.  
  372. void wxSizer::Clear( bool delete_windows )
  373. {
  374.     // First clear the ContainingSizer pointers
  375.     wxNode *node = m_children.First();
  376.     while (node)
  377.     {
  378.         wxSizerItem *item = (wxSizerItem*)node->Data();
  379.         if (item->IsWindow())
  380.             item->GetWindow()->SetContainingSizer(NULL);
  381.         node = node->Next();
  382.     }
  383.  
  384.     // Destroy the windows if needed
  385.     if (delete_windows)
  386.         DeleteWindows();
  387.  
  388.     // Now empty the list
  389.     m_children.Clear();
  390. }
  391.  
  392. void wxSizer::DeleteWindows()
  393. {
  394.     wxNode *node = m_children.First();
  395.     while (node)
  396.     {
  397.         wxSizerItem *item = (wxSizerItem*)node->Data();
  398.         item->DeleteWindows();
  399.         node = node->Next();
  400.     }
  401. }
  402.  
  403. wxSize wxSizer::Fit( wxWindow *window )
  404. {
  405.     wxSize size;
  406.     if (window->IsTopLevel())
  407.         size = FitSize( window );
  408.     else
  409.         size = GetMinWindowSize( window );
  410.  
  411.     window->SetSize( size );
  412.  
  413.     return size;
  414. }
  415.  
  416. void wxSizer::FitInside( wxWindow *window )
  417. {
  418.     wxSize size;
  419.     if (window->IsTopLevel())
  420.         size = VirtualFitSize( window );
  421.     else
  422.         size = GetMinClientSize( window );
  423.  
  424.     window->SetVirtualSize( size );
  425. }
  426.  
  427. void wxSizer::Layout()
  428. {
  429.     CalcMin();
  430.     RecalcSizes();
  431. }
  432.  
  433. void wxSizer::SetSizeHints( wxWindow *window )
  434. {
  435.     // Preserve the window's max size hints, but set the
  436.     // lower bound according to the sizer calculations.
  437.  
  438.     wxSize size = Fit( window );
  439.  
  440.     window->SetSizeHints( size.x,
  441.                           size.y,
  442.                           window->GetMaxWidth(),
  443.                           window->GetMaxHeight() );
  444. }
  445.  
  446. void wxSizer::SetVirtualSizeHints( wxWindow *window )
  447. {
  448.     // Preserve the window's max size hints, but set the
  449.     // lower bound according to the sizer calculations.
  450.  
  451.     FitInside( window );
  452.     wxSize size( window->GetVirtualSize() );
  453.     window->SetVirtualSizeHints( size.x,
  454.                                  size.y,
  455.                                  window->GetMaxWidth(),
  456.                                  window->GetMaxHeight() );
  457. }
  458.  
  459. wxSize wxSizer::GetMaxWindowSize( wxWindow *window )
  460. {
  461.     return window->GetMaxSize();
  462. }
  463.  
  464. wxSize wxSizer::GetMinWindowSize( wxWindow *window )
  465. {
  466.     wxSize minSize( GetMinSize() );
  467.     wxSize size( window->GetSize() );
  468.     wxSize client_size( window->GetClientSize() );
  469.     return wxSize( minSize.x+size.x-client_size.x,
  470.                    minSize.y+size.y-client_size.y );
  471. }
  472.  
  473. // Return a window size that will fit within the screens dimensions
  474. wxSize wxSizer::FitSize( wxWindow *window )
  475. {
  476.     wxSize size     = GetMinWindowSize( window );
  477.     wxSize sizeMax  = GetMaxWindowSize( window );
  478.  
  479.     // Limit the size if sizeMax != wxDefaultSize
  480.  
  481.     if ( size.x > sizeMax.x && sizeMax.x != -1 )
  482.         size.x = sizeMax.x;
  483.     if ( size.y > sizeMax.y && sizeMax.y != -1 )
  484.         size.y = sizeMax.y;
  485.  
  486.     return size;
  487. }
  488.  
  489. wxSize wxSizer::GetMaxClientSize( wxWindow *window )
  490. {
  491.     wxSize maxSize( window->GetMaxSize() );
  492.  
  493.     if( maxSize != wxDefaultSize )
  494.     {
  495.         wxSize size( window->GetSize() );
  496.         wxSize client_size( window->GetClientSize() );
  497.  
  498.         return wxSize( maxSize.x + client_size.x - size.x,
  499.                        maxSize.y + client_size.y - size.y );
  500.     }
  501.     else
  502.         return wxDefaultSize;
  503. }
  504.  
  505. wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
  506. {
  507.     return GetMinSize();  // Already returns client size.
  508. }
  509.  
  510. wxSize wxSizer::VirtualFitSize( wxWindow *window )
  511. {
  512.     wxSize size     = GetMinClientSize( window );
  513.     wxSize sizeMax  = GetMaxClientSize( window );
  514.  
  515.     // Limit the size if sizeMax != wxDefaultSize
  516.  
  517.     if ( size.x > sizeMax.x && sizeMax.x != -1 )
  518.         size.x = sizeMax.x;
  519.     if ( size.y > sizeMax.y && sizeMax.y != -1 )
  520.         size.y = sizeMax.y;
  521.  
  522.     return size;
  523. }
  524.  
  525. void wxSizer::SetDimension( int x, int y, int width, int height )
  526. {
  527.     m_position.x = x;
  528.     m_position.y = y;
  529.     m_size.x = width;
  530.     m_size.y = height;
  531.     CalcMin();
  532.     RecalcSizes();
  533. }
  534.  
  535. wxSize wxSizer::GetMinSize()
  536. {
  537.     wxSize ret( CalcMin() );
  538.     if (ret.x < m_minSize.x) ret.x = m_minSize.x;
  539.     if (ret.y < m_minSize.y) ret.y = m_minSize.y;
  540.     return ret;
  541. }
  542.  
  543. void wxSizer::DoSetMinSize( int width, int height )
  544. {
  545.     m_minSize.x = width;
  546.     m_minSize.y = height;
  547. }
  548.  
  549. bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
  550. {
  551.     wxASSERT( window );
  552.  
  553.     wxNode *node = m_children.First();
  554.     while (node)
  555.     {
  556.         wxSizerItem *item = (wxSizerItem*)node->Data();
  557.         if (item->GetWindow() == window)
  558.         {
  559.             item->SetInitSize( width, height );
  560.             return TRUE;
  561.         }
  562.         node = node->Next();
  563.     }
  564.  
  565.     node = m_children.First();
  566.     while (node)
  567.     {
  568.         wxSizerItem *item = (wxSizerItem*)node->Data();
  569.         if (item->GetSizer())
  570.         {
  571.             // It's a sizer, so lets search recursively.
  572.             if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
  573.             {
  574.                 // A child sizer found the requested windw, exit.
  575.                 return TRUE;
  576.             }
  577.         }
  578.         node = node->Next();
  579.     }
  580.  
  581.     return FALSE;
  582. }
  583.  
  584. bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
  585. {
  586.     wxASSERT( sizer );
  587.  
  588.     wxNode *node = m_children.First();
  589.     while (node)
  590.     {
  591.         wxSizerItem *item = (wxSizerItem*)node->Data();
  592.         if (item->GetSizer() == sizer)
  593.         {
  594.             item->GetSizer()->DoSetMinSize( width, height );
  595.             return TRUE;
  596.         }
  597.         node = node->Next();
  598.     }
  599.  
  600.     node = m_children.First();
  601.     while (node)
  602.     {
  603.         wxSizerItem *item = (wxSizerItem*)node->Data();
  604.         if (item->GetSizer())
  605.         {
  606.             // It's a sizer, so lets search recursively.
  607.             if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
  608.             {
  609.                 // A child sizer found the requested windw, exit.
  610.                 return TRUE;
  611.             }
  612.         }
  613.         node = node->Next();
  614.     }
  615.  
  616.     return FALSE;
  617. }
  618.  
  619. bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
  620. {
  621.     wxNode *node = m_children.Nth( pos );
  622.     if (!node) return FALSE;
  623.  
  624.     wxSizerItem *item = (wxSizerItem*) node->Data();
  625.     if (item->GetSizer())
  626.     {
  627.         // Sizers contains the minimal size in them, if not calculated ...
  628.         item->GetSizer()->DoSetMinSize( width, height );
  629.     }
  630.     else
  631.     {
  632.         // ... but the minimal size of spacers and windows in stored in them
  633.         item->SetInitSize( width, height );
  634.     }
  635.  
  636.     return TRUE;
  637. }
  638.  
  639. //---------------------------------------------------------------------------
  640. // wxGridSizer
  641. //---------------------------------------------------------------------------
  642.  
  643. wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
  644. {
  645.     m_rows = rows;
  646.     m_cols = cols;
  647.     m_vgap = vgap;
  648.     m_hgap = hgap;
  649. }
  650.  
  651. wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
  652. {
  653.     m_rows = 0;
  654.     m_cols = cols;
  655.     m_vgap = vgap;
  656.     m_hgap = hgap;
  657. }
  658.  
  659. int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
  660. {
  661.     int nitems = m_children.GetCount();
  662.     if ( nitems) 
  663.     {
  664.         if ( m_cols )
  665.         {
  666.             ncols = m_cols;
  667.             nrows = (nitems + m_cols - 1) / m_cols;
  668.         }
  669.         else if ( m_rows )
  670.         {
  671.             ncols = (nitems + m_rows - 1) / m_rows;
  672.             nrows = m_rows;
  673.         }
  674.         else // 0 columns, 0 rows?
  675.         {
  676.             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
  677.  
  678.             nrows = ncols = 0;
  679.         }
  680.     }
  681.  
  682.     return nitems;
  683. }
  684.  
  685. void wxGridSizer::RecalcSizes()
  686. {
  687.     int nitems, nrows, ncols;
  688.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  689.         return;
  690.  
  691.     wxSize sz( GetSize() );
  692.     wxPoint pt( GetPosition() );
  693.  
  694.     int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
  695.     int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
  696.  
  697.     int x = pt.x;
  698.     for (int c = 0; c < ncols; c++)
  699.     {
  700.         int y = pt.y;
  701.         for (int r = 0; r < nrows; r++)
  702.         {
  703.             int i = r * ncols + c;
  704.             if (i < nitems)
  705.             {
  706.                 wxNode *node = m_children.Nth( i );
  707.                 wxASSERT( node );
  708.  
  709.                 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
  710.             }
  711.             y = y + h + m_vgap;
  712.         }
  713.         x = x + w + m_hgap;
  714.     }
  715. }
  716.  
  717. wxSize wxGridSizer::CalcMin()
  718. {
  719.     int nitems, nrows, ncols;
  720.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  721.         return wxSize(10, 10);
  722.  
  723.     // Find the max width and height for any component
  724.     int w = 0;
  725.     int h = 0;
  726.  
  727.     wxNode *node = m_children.First();
  728.     while (node)
  729.     {
  730.         wxSizerItem *item = (wxSizerItem*)node->Data();
  731.         wxSize sz( item->CalcMin() );
  732.         w = wxMax( w, sz.x );
  733.         h = wxMax( h, sz.y );
  734.  
  735.         node = node->Next();
  736.     }
  737.  
  738.     return wxSize(ncols * w + (ncols-1) * m_hgap,
  739.                   nrows * h + (nrows-1) * m_vgap);
  740. }
  741.  
  742. void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
  743. {
  744.     wxPoint pt( x,y );
  745.     wxSize sz( item->CalcMin() );
  746.     int flag = item->GetFlag();
  747.  
  748.     if ((flag & wxEXPAND) || (flag & wxSHAPED))
  749.     {
  750.        sz = wxSize(w, h);
  751.     }
  752.     else
  753.     {
  754.         if (flag & wxALIGN_CENTER_HORIZONTAL)
  755.         {
  756.             pt.x = x + (w - sz.x) / 2;
  757.         }
  758.         else if (flag & wxALIGN_RIGHT)
  759.         {
  760.             pt.x = x + (w - sz.x);
  761.         }
  762.  
  763.         if (flag & wxALIGN_CENTER_VERTICAL)
  764.         {
  765.             pt.y = y + (h - sz.y) / 2;
  766.         }
  767.         else if (flag & wxALIGN_BOTTOM)
  768.         {
  769.             pt.y = y + (h - sz.y);
  770.         }
  771.     }
  772.  
  773.     item->SetDimension(pt, sz);
  774. }
  775.  
  776. //---------------------------------------------------------------------------
  777. // wxFlexGridSizer
  778. //---------------------------------------------------------------------------
  779.  
  780. wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
  781.    : wxGridSizer( rows, cols, vgap, hgap )
  782. {
  783.     m_rowHeights = (int*) NULL;
  784.     m_colWidths = (int*) NULL;
  785. }
  786.  
  787. wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
  788.    : wxGridSizer( cols, vgap, hgap )
  789. {
  790.     m_rowHeights = (int*) NULL;
  791.     m_colWidths = (int*) NULL;
  792. }
  793.  
  794. wxFlexGridSizer::~wxFlexGridSizer()
  795. {
  796.     if (m_rowHeights)
  797.         delete[] m_rowHeights;
  798.     if (m_colWidths)
  799.         delete[] m_colWidths;
  800. }
  801.  
  802. void wxFlexGridSizer::CreateArrays()
  803. {
  804.     if (m_rowHeights)
  805.         delete[] m_rowHeights;
  806.     if (m_colWidths)
  807.         delete[] m_colWidths;
  808.  
  809.     int nitems, nrows, ncols;
  810.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  811.     {
  812.         m_rowHeights =
  813.         m_colWidths = NULL;
  814.     }
  815.  
  816.     m_rowHeights = new int[nrows];
  817.     m_colWidths = new int[ncols];
  818.  
  819.     for (int col = 0; col < ncols; col++)
  820.         m_colWidths[ col ] = 0;
  821.     for (int row = 0; row < nrows; row++)
  822.         m_rowHeights[ row ] = 0;
  823. }
  824.  
  825. void wxFlexGridSizer::RecalcSizes()
  826. {
  827.     int nitems, nrows, ncols;
  828.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  829.         return;
  830.  
  831.     wxSize sz( GetSize() );
  832.     wxSize minsz( CalcMin() );
  833.     wxPoint pt( GetPosition() );
  834.     int    delta;
  835.     size_t idx,num;
  836.     wxArrayInt temp;
  837.  
  838.     // Transfer only those rows into temp which exist in the sizer
  839.     // ignoring the superflouus ones. This prevents a segfault when
  840.     // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
  841.     for (idx = 0; idx < m_growableRows.GetCount(); idx++)
  842.         if (m_growableRows[idx] < nrows)
  843.             temp.Add( m_growableRows[idx] );
  844.     num = temp.GetCount();
  845.  
  846.     if ((num > 0) && (sz.y > minsz.y))
  847.     {
  848.         delta = (sz.y - minsz.y) / num;
  849.         for (idx = 0; idx < num; idx++)
  850.             m_rowHeights[ temp[idx] ] += delta;
  851.     }
  852.  
  853.     temp.Empty();
  854.     // See above
  855.     for (idx = 0; idx < m_growableCols.GetCount(); idx++)
  856.         if (m_growableCols[idx] < ncols)
  857.             temp.Add( m_growableCols[idx] );
  858.     num = temp.GetCount();
  859.  
  860.     if ((num > 0) && (sz.x > minsz.x))
  861.     {
  862.         delta = (sz.x - minsz.x) / num;
  863.         for (idx = 0; idx < num; idx++)
  864.             m_colWidths[ temp[idx] ] += delta;
  865.     }
  866.  
  867.     sz = wxSize( pt.x + sz.x, pt.y + sz.y );
  868.  
  869.     int x = pt.x;
  870.     for (int c = 0; c < ncols; c++)
  871.     {
  872.         int y = pt.y;
  873.         for (int r = 0; r < nrows; r++)
  874.         {
  875.             int i = r * ncols + c;
  876.             if (i < nitems)
  877.             {
  878.                 wxNode *node = m_children.Nth( i );
  879.                 wxASSERT( node );
  880.  
  881.                 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
  882.                 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
  883.  
  884.                 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
  885.             }
  886.             y = y + m_rowHeights[r] + m_vgap;
  887.         }
  888.         x = x + m_colWidths[c] + m_hgap;
  889.     }
  890. }
  891.  
  892. wxSize wxFlexGridSizer::CalcMin()
  893. {
  894.     int nitems, nrows, ncols;
  895.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  896.         return wxSize(10,10);
  897.  
  898.     CreateArrays();
  899.  
  900.     int i = 0;
  901.     wxNode *node = m_children.First();
  902.     while (node)
  903.     {
  904.         wxSizerItem *item = (wxSizerItem*)node->Data();
  905.         wxSize sz( item->CalcMin() );
  906.         int row = i / ncols;
  907.         int col = i % ncols;
  908.         m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
  909.         m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
  910.  
  911.         node = node->Next();
  912.         i++;
  913.     }
  914.  
  915.     int width = 0;
  916.     for (int col = 0; col < ncols; col++)
  917.         width += m_colWidths[ col ];
  918.  
  919.     int height = 0;
  920.     for (int row = 0; row < nrows; row++)
  921.         height += m_rowHeights[ row ];
  922.  
  923.     return wxSize( width +  (ncols-1) * m_hgap,
  924.                    height + (nrows-1) * m_vgap);
  925. }
  926.  
  927. void wxFlexGridSizer::AddGrowableRow( size_t idx )
  928. {
  929.     m_growableRows.Add( idx );
  930. }
  931.  
  932. void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
  933. {
  934. }
  935.  
  936. void wxFlexGridSizer::AddGrowableCol( size_t idx )
  937. {
  938.     m_growableCols.Add( idx );
  939. }
  940.  
  941. void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
  942. {
  943. }
  944.  
  945. //---------------------------------------------------------------------------
  946. // wxBoxSizer
  947. //---------------------------------------------------------------------------
  948.  
  949. wxBoxSizer::wxBoxSizer( int orient )
  950. {
  951.     m_orient = orient;
  952. }
  953.  
  954. void wxBoxSizer::RecalcSizes()
  955. {
  956.     if (m_children.GetCount() == 0)
  957.         return;
  958.  
  959.     int delta = 0;
  960.     int extra = 0;
  961.     if (m_stretchable)
  962.     {
  963.         if (m_orient == wxHORIZONTAL)
  964.         {
  965.             delta = (m_size.x - m_fixedWidth) / m_stretchable;
  966.             extra = (m_size.x - m_fixedWidth) % m_stretchable;
  967.         }
  968.         else
  969.         {
  970.             delta = (m_size.y - m_fixedHeight) / m_stretchable;
  971.             extra = (m_size.y - m_fixedHeight) % m_stretchable;
  972.         }
  973.     }
  974.  
  975.     wxPoint pt( m_position );
  976.  
  977.     wxNode *node = m_children.GetFirst();
  978.     while (node)
  979.     {
  980.         wxSizerItem *item = (wxSizerItem*) node->Data();
  981.  
  982.         int weight = 1;
  983.         if (item->GetOption())
  984.             weight = item->GetOption();
  985.  
  986.         wxSize size( item->CalcMin() );
  987.  
  988.         if (m_orient == wxVERTICAL)
  989.         {
  990.             wxCoord height = size.y;
  991.             if (item->GetOption())
  992.             {
  993.                 height = (delta * weight) + extra;
  994.                 extra = 0; // only the first item will get the remainder as extra size
  995.             }
  996.  
  997.             wxPoint child_pos( pt );
  998.             wxSize  child_size( wxSize( size.x, height) );
  999.  
  1000.             if (item->GetFlag() & (wxEXPAND | wxSHAPED))
  1001.                 child_size.x = m_size.x;
  1002.             else if (item->GetFlag() & wxALIGN_RIGHT)
  1003.                 child_pos.x += m_size.x - size.x;
  1004.             else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
  1005.             // XXX wxCENTER is added for backward compatibility;
  1006.             //     wxALIGN_CENTER should be used in new code
  1007.                 child_pos.x += (m_size.x - size.x) / 2;
  1008.  
  1009.             item->SetDimension( child_pos, child_size );
  1010.  
  1011.             pt.y += height;
  1012.         }
  1013.         else
  1014.         {
  1015.             wxCoord width = size.x;
  1016.             if (item->GetOption())
  1017.             {
  1018.                 width = (delta * weight) + extra;
  1019.                 extra = 0; // only the first item will get the remainder as extra size
  1020.             }
  1021.  
  1022.             wxPoint child_pos( pt );
  1023.             wxSize  child_size( wxSize(width, size.y) );
  1024.  
  1025.             if (item->GetFlag() & (wxEXPAND | wxSHAPED))
  1026.                 child_size.y = m_size.y;
  1027.             else if (item->GetFlag() & wxALIGN_BOTTOM)
  1028.                 child_pos.y += m_size.y - size.y;
  1029.             else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
  1030.             // XXX wxCENTER is added for backward compatibility;
  1031.             //     wxALIGN_CENTER should be used in new code
  1032.                 child_pos.y += (m_size.y - size.y) / 2;
  1033.  
  1034.             item->SetDimension( child_pos, child_size );
  1035.  
  1036.             pt.x += width;
  1037.         }
  1038.  
  1039.         node = node->Next();
  1040.     }
  1041. }
  1042.  
  1043. wxSize wxBoxSizer::CalcMin()
  1044. {
  1045.     if (m_children.GetCount() == 0)
  1046.         return wxSize(10,10);
  1047.  
  1048.     m_stretchable = 0;
  1049.     m_minWidth = 0;
  1050.     m_minHeight = 0;
  1051.     m_fixedWidth = 0;
  1052.     m_fixedHeight = 0;
  1053.  
  1054.     // Find how long each stretch unit needs to be
  1055.     int stretchSize = 1;
  1056.     wxNode *node = m_children.GetFirst();
  1057.     while (node)
  1058.     {
  1059.         wxSizerItem *item = (wxSizerItem*) node->Data();
  1060.         if (item->GetOption() != 0)
  1061.         {
  1062.             int stretch = item->GetOption();
  1063.             wxSize size( item->CalcMin() );
  1064.             int sizePerStretch;
  1065.             // Integer division rounded up is (a + b - 1) / b
  1066.             if (m_orient == wxHORIZONTAL)
  1067.                 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
  1068.             else
  1069.                 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
  1070.             if (sizePerStretch > stretchSize)
  1071.                 stretchSize = sizePerStretch;
  1072.         }
  1073.         node = node->Next();
  1074.     }
  1075.     // Calculate overall minimum size
  1076.     node = m_children.GetFirst();
  1077.     while (node)
  1078.     {
  1079.         wxSizerItem *item = (wxSizerItem*) node->Data();
  1080.  
  1081.         m_stretchable += item->GetOption();
  1082.  
  1083.         wxSize size( item->CalcMin() );
  1084.         if (item->GetOption() != 0)
  1085.         {
  1086.             if (m_orient == wxHORIZONTAL)
  1087.                 size.x = stretchSize * item->GetOption();
  1088.             else
  1089.                 size.y = stretchSize * item->GetOption();
  1090.         }
  1091.  
  1092.         if (m_orient == wxHORIZONTAL)
  1093.         {
  1094.             m_minWidth += size.x;
  1095.             m_minHeight = wxMax( m_minHeight, size.y );
  1096.         }
  1097.         else
  1098.         {
  1099.             m_minHeight += size.y;
  1100.             m_minWidth = wxMax( m_minWidth, size.x );
  1101.         }
  1102.  
  1103.         if (item->GetOption() == 0)
  1104.         {
  1105.             if (m_orient == wxVERTICAL)
  1106.             {
  1107.                 m_fixedHeight += size.y;
  1108.                 m_fixedWidth = wxMax( m_fixedWidth, size.x );
  1109.             }
  1110.             else
  1111.             {
  1112.                 m_fixedWidth += size.x;
  1113.                 m_fixedHeight = wxMax( m_fixedHeight, size.y );
  1114.             }
  1115.         }
  1116.  
  1117.         node = node->Next();
  1118.     }
  1119.  
  1120.     return wxSize( m_minWidth, m_minHeight );
  1121. }
  1122.  
  1123. //---------------------------------------------------------------------------
  1124. // wxStaticBoxSizer
  1125. //---------------------------------------------------------------------------
  1126.  
  1127. #if wxUSE_STATBOX
  1128.  
  1129. wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
  1130.                 : wxBoxSizer( orient )
  1131. {
  1132.     wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
  1133.  
  1134.     m_staticBox = box;
  1135. }
  1136.  
  1137. static void GetStaticBoxBorders(wxStaticBox *box,
  1138.                                 int *borderTop, int *borderOther)
  1139. {
  1140.     // this has to be done platform by platform as there is no way to
  1141.     // guess the thickness of a wxStaticBox border
  1142. #ifdef __WXGTK__
  1143.     if ( box->GetLabel().IsEmpty() )
  1144.         *borderTop = 5;
  1145.     else
  1146. #endif // __WXGTK__
  1147.         *borderTop = 15;
  1148.     (void)box;
  1149.     *borderOther = 5;
  1150. }
  1151.  
  1152. void wxStaticBoxSizer::RecalcSizes()
  1153. {
  1154.     int top_border, other_border;
  1155.     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
  1156.  
  1157.     m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
  1158.  
  1159.     wxPoint old_pos( m_position );
  1160.     m_position.x += other_border;
  1161.     m_position.y += top_border;
  1162.     wxSize old_size( m_size );
  1163.     m_size.x -= 2*other_border;
  1164.     m_size.y -= top_border + other_border;
  1165.  
  1166.     wxBoxSizer::RecalcSizes();
  1167.  
  1168.     m_position = old_pos;
  1169.     m_size = old_size;
  1170. }
  1171.  
  1172. wxSize wxStaticBoxSizer::CalcMin()
  1173. {
  1174.     int top_border, other_border;
  1175.     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
  1176.  
  1177.     wxSize ret( wxBoxSizer::CalcMin() );
  1178.     ret.x += 2*other_border;
  1179.     ret.y += other_border + top_border;
  1180.  
  1181.     return ret;
  1182. }
  1183.  
  1184. #endif // wxUSE_STATBOX
  1185.  
  1186. //---------------------------------------------------------------------------
  1187. // wxNotebookSizer
  1188. //---------------------------------------------------------------------------
  1189.  
  1190. #if wxUSE_NOTEBOOK
  1191.  
  1192. wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
  1193. {
  1194.     wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
  1195.  
  1196.     m_notebook = nb;
  1197. }
  1198.  
  1199. void wxNotebookSizer::RecalcSizes()
  1200. {
  1201.     m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
  1202. }
  1203.  
  1204. wxSize wxNotebookSizer::CalcMin()
  1205. {
  1206.     wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
  1207.  
  1208.     sizeBorder.x += 5;
  1209.     sizeBorder.y += 5;
  1210.  
  1211.     if (m_notebook->GetChildren().GetCount() == 0)
  1212.     {
  1213.         return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
  1214.     }
  1215.  
  1216.     int maxX = 0;
  1217.     int maxY = 0;
  1218.  
  1219.     wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
  1220.     while (node)
  1221.     {
  1222.         wxWindow *item = node->GetData();
  1223.         wxSizer *itemsizer = item->GetSizer();
  1224.  
  1225.         if (itemsizer)
  1226.         {
  1227.             wxSize subsize( itemsizer->CalcMin() );
  1228.  
  1229.             if (subsize.x > maxX)
  1230.                 maxX = subsize.x;
  1231.             if (subsize.y > maxY)
  1232.                 maxY = subsize.y;
  1233.         }
  1234.  
  1235.         node = node->GetNext();
  1236.     }
  1237.  
  1238.     return wxSize( maxX, maxY ) + sizeBorder;
  1239. }
  1240.  
  1241. #endif // wxUSE_NOTEBOOK
  1242.  
  1243. // vi:sts=4:sw=4:et
  1244.