home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / sizer.cpp < prev    next >
C/C++ Source or Header  |  2002-11-09  |  35KB  |  1,332 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.2.4 2002/11/09 13:29:22 RL 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_show = TRUE;                // Cannot be changed
  54.     m_userData = userData;
  55.  
  56.     // minimal size is the initial size
  57.     m_minSize.x = width;
  58.     m_minSize.y = height;
  59.  
  60.     SetRatio(width, height);
  61.  
  62.     // size is set directly
  63.     m_size = m_minSize;
  64. }
  65.  
  66. wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
  67. {
  68.     m_window = window;
  69.     m_sizer = (wxSizer *) NULL;
  70.     m_option = option;
  71.     m_border = border;
  72.     m_flag = flag;
  73.     m_show = TRUE;
  74.     m_userData = userData;
  75.  
  76.     // minimal size is the initial size
  77.     m_minSize = window->GetSize();
  78.  
  79.     // aspect ratio calculated from initial size
  80.     SetRatio(m_minSize);
  81.  
  82.     // size is calculated later
  83.     // m_size = ...
  84. }
  85.  
  86. wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
  87. {
  88.     m_window = (wxWindow *) NULL;
  89.     m_sizer = sizer;
  90.     m_option = option;
  91.     m_border = border;
  92.     m_flag = flag;
  93.     m_show = TRUE;
  94.     m_userData = userData;
  95.  
  96.     // minimal size is calculated later
  97.     // m_minSize = ...
  98.     m_ratio = 0;
  99.  
  100.     // size is calculated later
  101.     // m_size = ...
  102. }
  103.  
  104. wxSizerItem::~wxSizerItem()
  105. {
  106.     if (m_userData)
  107.         delete m_userData;
  108.     if (m_sizer)
  109.         delete m_sizer;
  110. }
  111.  
  112.  
  113. wxSize wxSizerItem::GetSize()
  114. {
  115.     wxSize ret;
  116.     if (IsSizer())
  117.         ret = m_sizer->GetSize();
  118.     else
  119.     if (IsWindow())
  120.         ret = m_window->GetSize();
  121.     else ret = m_size;
  122.  
  123.     if (m_flag & wxWEST)
  124.         ret.x += m_border;
  125.     if (m_flag & wxEAST)
  126.         ret.x += m_border;
  127.     if (m_flag & wxNORTH)
  128.         ret.y += m_border;
  129.     if (m_flag & wxSOUTH)
  130.         ret.y += m_border;
  131.  
  132.     return ret;
  133. }
  134.  
  135. wxSize wxSizerItem::CalcMin()
  136. {
  137.     wxSize ret;
  138.     if (IsSizer())
  139.     {
  140.         ret = m_sizer->GetMinSize();
  141.  
  142.         // if we have to preserve aspect ratio _AND_ this is
  143.         // the first-time calculation, consider ret to be initial size
  144.         if ((m_flag & wxSHAPED) && !m_ratio)
  145.             SetRatio(ret);
  146.     }
  147.     else
  148.     {
  149.         if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
  150.         {
  151.             // By user request, keep the minimal size for this item
  152.             // in sync with the largest of BestSize and any user supplied
  153.             // minimum size hint.  Useful in cases where the item is
  154.             // changeable -- static text labels, etc.
  155.             m_minSize = m_window->GetAdjustedBestSize();
  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.     if ((size_t)pos >= m_children.GetCount())
  365.         return FALSE;
  366.     wxNode *node = m_children.Nth( pos );
  367.     if (!node) return FALSE;
  368.  
  369.     m_children.DeleteNode( node );
  370.  
  371.     return TRUE;
  372. }
  373.  
  374. void wxSizer::Clear( bool delete_windows )
  375. {
  376.     // First clear the ContainingSizer pointers
  377.     wxNode *node = m_children.First();
  378.     while (node)
  379.     {
  380.         wxSizerItem *item = (wxSizerItem*)node->Data();
  381.         if (item->IsWindow())
  382.             item->GetWindow()->SetContainingSizer(NULL);
  383.         node = node->Next();
  384.     }
  385.  
  386.     // Destroy the windows if needed
  387.     if (delete_windows)
  388.         DeleteWindows();
  389.  
  390.     // Now empty the list
  391.     m_children.Clear();
  392. }
  393.  
  394. void wxSizer::DeleteWindows()
  395. {
  396.     wxNode *node = m_children.First();
  397.     while (node)
  398.     {
  399.         wxSizerItem *item = (wxSizerItem*)node->Data();
  400.         item->DeleteWindows();
  401.         node = node->Next();
  402.     }
  403. }
  404.  
  405. wxSize wxSizer::Fit( wxWindow *window )
  406. {
  407.     wxSize size;
  408.     if (window->IsTopLevel())
  409.         size = FitSize( window );
  410.     else
  411.         size = GetMinWindowSize( window );
  412.  
  413.     window->SetSize( size );
  414.  
  415.     return size;
  416. }
  417.  
  418. void wxSizer::FitInside( wxWindow *window )
  419. {
  420.     wxSize size;
  421.     if (window->IsTopLevel())
  422.         size = VirtualFitSize( window );
  423.     else
  424.         size = GetMinClientSize( window );
  425.  
  426.     window->SetVirtualSize( size );
  427. }
  428.  
  429. void wxSizer::Layout()
  430. {
  431.     CalcMin();
  432.     RecalcSizes();
  433. }
  434.  
  435. void wxSizer::SetSizeHints( wxWindow *window )
  436. {
  437.     // Preserve the window's max size hints, but set the
  438.     // lower bound according to the sizer calculations.
  439.  
  440.     wxSize size = Fit( window );
  441.  
  442.     window->SetSizeHints( size.x,
  443.                           size.y,
  444.                           window->GetMaxWidth(),
  445.                           window->GetMaxHeight() );
  446. }
  447.  
  448. void wxSizer::SetVirtualSizeHints( wxWindow *window )
  449. {
  450.     // Preserve the window's max size hints, but set the
  451.     // lower bound according to the sizer calculations.
  452.  
  453.     FitInside( window );
  454.     wxSize size( window->GetVirtualSize() );
  455.     window->SetVirtualSizeHints( size.x,
  456.                                  size.y,
  457.                                  window->GetMaxWidth(),
  458.                                  window->GetMaxHeight() );
  459. }
  460.  
  461. wxSize wxSizer::GetMaxWindowSize( wxWindow *window )
  462. {
  463.     return window->GetMaxSize();
  464. }
  465.  
  466. wxSize wxSizer::GetMinWindowSize( wxWindow *window )
  467. {
  468.     wxSize minSize( GetMinSize() );
  469.     wxSize size( window->GetSize() );
  470.     wxSize client_size( window->GetClientSize() );
  471.     return wxSize( minSize.x+size.x-client_size.x,
  472.                    minSize.y+size.y-client_size.y );
  473. }
  474.  
  475. // Return a window size that will fit within the screens dimensions
  476. wxSize wxSizer::FitSize( wxWindow *window )
  477. {
  478.     wxSize size     = GetMinWindowSize( window );
  479.     wxSize sizeMax  = GetMaxWindowSize( window );
  480.  
  481.     // Limit the size if sizeMax != wxDefaultSize
  482.  
  483.     if ( size.x > sizeMax.x && sizeMax.x != -1 )
  484.         size.x = sizeMax.x;
  485.     if ( size.y > sizeMax.y && sizeMax.y != -1 )
  486.         size.y = sizeMax.y;
  487.  
  488.     return size;
  489. }
  490.  
  491. wxSize wxSizer::GetMaxClientSize( wxWindow *window )
  492. {
  493.     wxSize maxSize( window->GetMaxSize() );
  494.  
  495.     if( maxSize != wxDefaultSize )
  496.     {
  497.         wxSize size( window->GetSize() );
  498.         wxSize client_size( window->GetClientSize() );
  499.  
  500.         return wxSize( maxSize.x + client_size.x - size.x,
  501.                        maxSize.y + client_size.y - size.y );
  502.     }
  503.     else
  504.         return wxDefaultSize;
  505. }
  506.  
  507. wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
  508. {
  509.     return GetMinSize();  // Already returns client size.
  510. }
  511.  
  512. wxSize wxSizer::VirtualFitSize( wxWindow *window )
  513. {
  514.     wxSize size     = GetMinClientSize( window );
  515.     wxSize sizeMax  = GetMaxClientSize( window );
  516.  
  517.     // Limit the size if sizeMax != wxDefaultSize
  518.  
  519.     if ( size.x > sizeMax.x && sizeMax.x != -1 )
  520.         size.x = sizeMax.x;
  521.     if ( size.y > sizeMax.y && sizeMax.y != -1 )
  522.         size.y = sizeMax.y;
  523.  
  524.     return size;
  525. }
  526.  
  527. void wxSizer::SetDimension( int x, int y, int width, int height )
  528. {
  529.     m_position.x = x;
  530.     m_position.y = y;
  531.     m_size.x = width;
  532.     m_size.y = height;
  533.     Layout();
  534. }
  535.  
  536. wxSize wxSizer::GetMinSize()
  537. {
  538.     wxSize ret( CalcMin() );
  539.     if (ret.x < m_minSize.x) ret.x = m_minSize.x;
  540.     if (ret.y < m_minSize.y) ret.y = m_minSize.y;
  541.     return ret;
  542. }
  543.  
  544. void wxSizer::DoSetMinSize( int width, int height )
  545. {
  546.     m_minSize.x = width;
  547.     m_minSize.y = height;
  548. }
  549.  
  550. bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
  551. {
  552.     wxASSERT( window );
  553.  
  554.     wxNode *node = m_children.First();
  555.     while (node)
  556.     {
  557.         wxSizerItem *item = (wxSizerItem*)node->Data();
  558.         if (item->GetWindow() == window)
  559.         {
  560.             item->SetInitSize( width, height );
  561.             return TRUE;
  562.         }
  563.         node = node->Next();
  564.     }
  565.  
  566.     node = m_children.First();
  567.     while (node)
  568.     {
  569.         wxSizerItem *item = (wxSizerItem*)node->Data();
  570.         if (item->GetSizer())
  571.         {
  572.             // It's a sizer, so lets search recursively.
  573.             if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
  574.             {
  575.                 // A child sizer found the requested windw, exit.
  576.                 return TRUE;
  577.             }
  578.         }
  579.         node = node->Next();
  580.     }
  581.  
  582.     return FALSE;
  583. }
  584.  
  585. bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
  586. {
  587.     wxASSERT( sizer );
  588.  
  589.     wxNode *node = m_children.First();
  590.     while (node)
  591.     {
  592.         wxSizerItem *item = (wxSizerItem*)node->Data();
  593.         if (item->GetSizer() == sizer)
  594.         {
  595.             item->GetSizer()->DoSetMinSize( width, height );
  596.             return TRUE;
  597.         }
  598.         node = node->Next();
  599.     }
  600.  
  601.     node = m_children.First();
  602.     while (node)
  603.     {
  604.         wxSizerItem *item = (wxSizerItem*)node->Data();
  605.         if (item->GetSizer())
  606.         {
  607.             // It's a sizer, so lets search recursively.
  608.             if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
  609.             {
  610.                 // A child sizer found the requested windw, exit.
  611.                 return TRUE;
  612.             }
  613.         }
  614.         node = node->Next();
  615.     }
  616.  
  617.     return FALSE;
  618. }
  619.  
  620. bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
  621. {
  622.     wxNode *node = m_children.Nth( pos );
  623.     if (!node) return FALSE;
  624.  
  625.     wxSizerItem *item = (wxSizerItem*) node->Data();
  626.     if (item->GetSizer())
  627.     {
  628.         // Sizers contains the minimal size in them, if not calculated ...
  629.         item->GetSizer()->DoSetMinSize( width, height );
  630.     }
  631.     else
  632.     {
  633.         // ... but the minimal size of spacers and windows in stored in them
  634.         item->SetInitSize( width, height );
  635.     }
  636.  
  637.     return TRUE;
  638. }
  639.  
  640. void wxSizer::Show(wxWindow *window, bool show)
  641. {
  642.     wxNode *node = m_children.GetFirst();
  643.     while (node)
  644.     {
  645.         wxSizerItem *item = (wxSizerItem*) node->Data();
  646.  
  647.         if (item->IsWindow() && item->GetWindow() == window)
  648.         {
  649.             item->Show(show);
  650.             window->Show(show);
  651.             return;
  652.         }
  653.         node = node->Next();
  654.     }
  655. }
  656.  
  657. void wxSizer::Show(wxSizer *sizer, bool show)
  658. {
  659.     wxNode *node = m_children.GetFirst();
  660.     while (node)
  661.     {
  662.         wxSizerItem *item = (wxSizerItem*) node->Data();
  663.  
  664.         if (item->IsSizer() && item->GetSizer() == sizer)
  665.         {
  666.             item->Show(show);
  667.             sizer->ShowItems(show);
  668.             return;
  669.         }
  670.         node = node->Next();
  671.     }
  672. }
  673.  
  674. void wxSizer::ShowItems (bool show)
  675. {
  676.     wxNode *node = m_children.GetFirst();
  677.     while (node)
  678.     {
  679.         wxSizerItem *item = (wxSizerItem*) node->Data();
  680.  
  681.         if (item->IsWindow())
  682.             item->GetWindow()->Show (show);
  683.         else if (item->IsSizer())
  684.             item->GetSizer()->ShowItems (show);
  685.  
  686.         node = node->Next();
  687.     }
  688. }
  689.  
  690. bool wxSizer::IsShown (wxWindow *window)
  691. {
  692.     wxNode *node = m_children.GetFirst();
  693.     while (node)
  694.     {
  695.         wxSizerItem *item = (wxSizerItem*) node->Data();
  696.         
  697.         if (item->IsWindow() && item->GetWindow() == window)
  698.         {
  699.             return item->IsShown();
  700.         }
  701.         node = node->Next();
  702.     }
  703.  
  704.     return FALSE;
  705. }
  706.  
  707. bool wxSizer::IsShown (wxSizer *sizer)
  708. {
  709.     wxNode *node = m_children.GetFirst();
  710.     while (node)
  711.     {
  712.         wxSizerItem *item = (wxSizerItem*) node->Data();
  713.  
  714.         if (item->IsSizer() && item->GetSizer() == sizer)
  715.         {
  716.             return item->IsShown();
  717.         }
  718.         node = node->Next();
  719.     }
  720.  
  721.     return FALSE;
  722. }
  723.  
  724. //---------------------------------------------------------------------------
  725. // wxGridSizer
  726. //---------------------------------------------------------------------------
  727.  
  728. wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
  729. {
  730.     m_rows = rows;
  731.     m_cols = cols;
  732.     m_vgap = vgap;
  733.     m_hgap = hgap;
  734. }
  735.  
  736. wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
  737. {
  738.     m_rows = 0;
  739.     m_cols = cols;
  740.     m_vgap = vgap;
  741.     m_hgap = hgap;
  742. }
  743.  
  744. int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
  745. {
  746.     int nitems = m_children.GetCount();
  747.     if ( nitems)
  748.     {
  749.         if ( m_cols )
  750.         {
  751.             ncols = m_cols;
  752.             nrows = (nitems + m_cols - 1) / m_cols;
  753.         }
  754.         else if ( m_rows )
  755.         {
  756.             ncols = (nitems + m_rows - 1) / m_rows;
  757.             nrows = m_rows;
  758.         }
  759.         else // 0 columns, 0 rows?
  760.         {
  761.             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
  762.  
  763.             nrows = ncols = 0;
  764.         }
  765.     }
  766.  
  767.     return nitems;
  768. }
  769.  
  770. void wxGridSizer::RecalcSizes()
  771. {
  772.     int nitems, nrows, ncols;
  773.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  774.         return;
  775.  
  776.     wxSize sz( GetSize() );
  777.     wxPoint pt( GetPosition() );
  778.  
  779.     int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
  780.     int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
  781.  
  782.     int x = pt.x;
  783.     for (int c = 0; c < ncols; c++)
  784.     {
  785.         int y = pt.y;
  786.         for (int r = 0; r < nrows; r++)
  787.         {
  788.             int i = r * ncols + c;
  789.             if (i < nitems)
  790.             {
  791.                 wxNode *node = m_children.Nth( i );
  792.                 wxASSERT( node );
  793.  
  794.                 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
  795.             }
  796.             y = y + h + m_vgap;
  797.         }
  798.         x = x + w + m_hgap;
  799.     }
  800. }
  801.  
  802. wxSize wxGridSizer::CalcMin()
  803. {
  804.     int nitems, nrows, ncols;
  805.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  806.         return wxSize(10, 10);
  807.  
  808.     // Find the max width and height for any component
  809.     int w = 0;
  810.     int h = 0;
  811.  
  812.     wxNode *node = m_children.First();
  813.     while (node)
  814.     {
  815.         wxSizerItem *item = (wxSizerItem*)node->Data();
  816.         wxSize sz( item->CalcMin() );
  817.         w = wxMax( w, sz.x );
  818.         h = wxMax( h, sz.y );
  819.  
  820.         node = node->Next();
  821.     }
  822.  
  823.     return wxSize(ncols * w + (ncols-1) * m_hgap,
  824.                   nrows * h + (nrows-1) * m_vgap);
  825. }
  826.  
  827. void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
  828. {
  829.     wxPoint pt( x,y );
  830.     wxSize sz( item->CalcMin() );
  831.     int flag = item->GetFlag();
  832.  
  833.     if ((flag & wxEXPAND) || (flag & wxSHAPED))
  834.     {
  835.        sz = wxSize(w, h);
  836.     }
  837.     else
  838.     {
  839.         if (flag & wxALIGN_CENTER_HORIZONTAL)
  840.         {
  841.             pt.x = x + (w - sz.x) / 2;
  842.         }
  843.         else if (flag & wxALIGN_RIGHT)
  844.         {
  845.             pt.x = x + (w - sz.x);
  846.         }
  847.  
  848.         if (flag & wxALIGN_CENTER_VERTICAL)
  849.         {
  850.             pt.y = y + (h - sz.y) / 2;
  851.         }
  852.         else if (flag & wxALIGN_BOTTOM)
  853.         {
  854.             pt.y = y + (h - sz.y);
  855.         }
  856.     }
  857.  
  858.     item->SetDimension(pt, sz);
  859. }
  860.  
  861. //---------------------------------------------------------------------------
  862. // wxFlexGridSizer
  863. //---------------------------------------------------------------------------
  864.  
  865. wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
  866.    : wxGridSizer( rows, cols, vgap, hgap )
  867. {
  868.     m_rowHeights = (int*) NULL;
  869.     m_colWidths = (int*) NULL;
  870. }
  871.  
  872. wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
  873.    : wxGridSizer( cols, vgap, hgap )
  874. {
  875.     m_rowHeights = (int*) NULL;
  876.     m_colWidths = (int*) NULL;
  877. }
  878.  
  879. wxFlexGridSizer::~wxFlexGridSizer()
  880. {
  881.     if (m_rowHeights)
  882.         delete[] m_rowHeights;
  883.     if (m_colWidths)
  884.         delete[] m_colWidths;
  885. }
  886.  
  887. void wxFlexGridSizer::CreateArrays()
  888. {
  889.     if (m_rowHeights)
  890.         delete[] m_rowHeights;
  891.     if (m_colWidths)
  892.         delete[] m_colWidths;
  893.  
  894.     int nitems, nrows, ncols;
  895.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  896.     {
  897.         m_rowHeights =
  898.         m_colWidths = NULL;
  899.     }
  900.  
  901.     m_rowHeights = new int[nrows];
  902.     m_colWidths = new int[ncols];
  903.  
  904.     for (int col = 0; col < ncols; col++)
  905.         m_colWidths[ col ] = 0;
  906.     for (int row = 0; row < nrows; row++)
  907.         m_rowHeights[ row ] = 0;
  908. }
  909.  
  910. void wxFlexGridSizer::RecalcSizes()
  911. {
  912.     int nitems, nrows, ncols;
  913.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  914.         return;
  915.  
  916.     wxSize sz( GetSize() );
  917.     wxSize minsz( CalcMin() );
  918.     wxPoint pt( GetPosition() );
  919.     int    delta;
  920.     size_t idx,num;
  921.     wxArrayInt temp;
  922.  
  923.     // Transfer only those rows into temp which exist in the sizer
  924.     // ignoring the superflouus ones. This prevents a segfault when
  925.     // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
  926.     for (idx = 0; idx < m_growableRows.GetCount(); idx++)
  927.         if (m_growableRows[idx] < nrows)
  928.             temp.Add( m_growableRows[idx] );
  929.     num = temp.GetCount();
  930.  
  931.     if ((num > 0) && (sz.y > minsz.y))
  932.     {
  933.         delta = (sz.y - minsz.y) / num;
  934.         for (idx = 0; idx < num; idx++)
  935.             m_rowHeights[ temp[idx] ] += delta;
  936.     }
  937.  
  938.     temp.Empty();
  939.     // See above
  940.     for (idx = 0; idx < m_growableCols.GetCount(); idx++)
  941.         if (m_growableCols[idx] < ncols)
  942.             temp.Add( m_growableCols[idx] );
  943.     num = temp.GetCount();
  944.  
  945.     if ((num > 0) && (sz.x > minsz.x))
  946.     {
  947.         delta = (sz.x - minsz.x) / num;
  948.         for (idx = 0; idx < num; idx++)
  949.             m_colWidths[ temp[idx] ] += delta;
  950.     }
  951.  
  952.     sz = wxSize( pt.x + sz.x, pt.y + sz.y );
  953.  
  954.     int x = pt.x;
  955.     for (int c = 0; c < ncols; c++)
  956.     {
  957.         int y = pt.y;
  958.         for (int r = 0; r < nrows; r++)
  959.         {
  960.             int i = r * ncols + c;
  961.             if (i < nitems)
  962.             {
  963.                 wxNode *node = m_children.Nth( i );
  964.                 wxASSERT( node );
  965.  
  966.                 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
  967.                 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
  968.  
  969.                 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
  970.             }
  971.             y = y + m_rowHeights[r] + m_vgap;
  972.         }
  973.         x = x + m_colWidths[c] + m_hgap;
  974.     }
  975. }
  976.  
  977. wxSize wxFlexGridSizer::CalcMin()
  978. {
  979.     int nitems, nrows, ncols;
  980.     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
  981.         return wxSize(10,10);
  982.  
  983.     CreateArrays();
  984.  
  985.     int i = 0;
  986.     wxNode *node = m_children.First();
  987.     while (node)
  988.     {
  989.         wxSizerItem *item = (wxSizerItem*)node->Data();
  990.         wxSize sz( item->CalcMin() );
  991.         int row = i / ncols;
  992.         int col = i % ncols;
  993.         m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
  994.         m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
  995.  
  996.         node = node->Next();
  997.         i++;
  998.     }
  999.  
  1000.     int width = 0;
  1001.     for (int col = 0; col < ncols; col++)
  1002.         width += m_colWidths[ col ];
  1003.  
  1004.     int height = 0;
  1005.     for (int row = 0; row < nrows; row++)
  1006.         height += m_rowHeights[ row ];
  1007.  
  1008.     return wxSize( width +  (ncols-1) * m_hgap,
  1009.                    height + (nrows-1) * m_vgap);
  1010. }
  1011.  
  1012. void wxFlexGridSizer::AddGrowableRow( size_t idx )
  1013. {
  1014.     m_growableRows.Add( idx );
  1015. }
  1016.  
  1017. void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
  1018. {
  1019. }
  1020.  
  1021. void wxFlexGridSizer::AddGrowableCol( size_t idx )
  1022. {
  1023.     m_growableCols.Add( idx );
  1024. }
  1025.  
  1026. void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
  1027. {
  1028. }
  1029.  
  1030. //---------------------------------------------------------------------------
  1031. // wxBoxSizer
  1032. //---------------------------------------------------------------------------
  1033.  
  1034. wxBoxSizer::wxBoxSizer( int orient )
  1035. {
  1036.     m_orient = orient;
  1037. }
  1038.  
  1039. void wxBoxSizer::RecalcSizes()
  1040. {
  1041.     if (m_children.GetCount() == 0)
  1042.         return;
  1043.  
  1044.     int delta = 0;
  1045.     int extra = 0;
  1046.     if (m_stretchable)
  1047.     {
  1048.         if (m_orient == wxHORIZONTAL)
  1049.         {
  1050.             delta = (m_size.x - m_fixedWidth) / m_stretchable;
  1051.             extra = (m_size.x - m_fixedWidth) % m_stretchable;
  1052.         }
  1053.         else
  1054.         {
  1055.             delta = (m_size.y - m_fixedHeight) / m_stretchable;
  1056.             extra = (m_size.y - m_fixedHeight) % m_stretchable;
  1057.         }
  1058.     }
  1059.  
  1060.     wxPoint pt( m_position );
  1061.  
  1062.     wxNode *node = m_children.GetFirst();
  1063.     while (node)
  1064.     {
  1065.         wxSizerItem *item = (wxSizerItem*) node->Data();
  1066.         if (item->IsShown())
  1067.         {
  1068.             int weight = 1;
  1069.             if (item->GetOption())
  1070.                 weight = item->GetOption();
  1071.  
  1072.             wxSize size( item->CalcMin() );
  1073.  
  1074.             if (m_orient == wxVERTICAL)
  1075.             {
  1076.                 wxCoord height = size.y;
  1077.                 if (item->GetOption())
  1078.                 {
  1079.                     height = (delta * weight) + extra;
  1080.                     extra = 0; // only the first item will get the remainder as extra size
  1081.                 }
  1082.  
  1083.                 wxPoint child_pos( pt );
  1084.                 wxSize  child_size( wxSize( size.x, height) );
  1085.  
  1086.                 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
  1087.                     child_size.x = m_size.x;
  1088.                 else if (item->GetFlag() & wxALIGN_RIGHT)
  1089.                     child_pos.x += m_size.x - size.x;
  1090.                 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
  1091.                 // XXX wxCENTER is added for backward compatibility;
  1092.                 //     wxALIGN_CENTER should be used in new code
  1093.                     child_pos.x += (m_size.x - size.x) / 2;
  1094.  
  1095.                 item->SetDimension( child_pos, child_size );
  1096.  
  1097.                 pt.y += height;
  1098.             }
  1099.             else
  1100.             {
  1101.                 wxCoord width = size.x;
  1102.                 if (item->GetOption())
  1103.                 {
  1104.                     width = (delta * weight) + extra;
  1105.                     extra = 0; // only the first item will get the remainder as extra size
  1106.                 }
  1107.  
  1108.                 wxPoint child_pos( pt );
  1109.                 wxSize  child_size( wxSize(width, size.y) );
  1110.  
  1111.                 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
  1112.                     child_size.y = m_size.y;
  1113.                 else if (item->GetFlag() & wxALIGN_BOTTOM)
  1114.                     child_pos.y += m_size.y - size.y;
  1115.                 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
  1116.                 // XXX wxCENTER is added for backward compatibility;
  1117.                 //     wxALIGN_CENTER should be used in new code
  1118.                     child_pos.y += (m_size.y - size.y) / 2;
  1119.  
  1120.                 item->SetDimension( child_pos, child_size );
  1121.  
  1122.                 pt.x += width;
  1123.             }
  1124.         }
  1125.  
  1126.         node = node->Next();
  1127.     }
  1128. }
  1129.  
  1130. wxSize wxBoxSizer::CalcMin()
  1131. {
  1132.     if (m_children.GetCount() == 0)
  1133.         return wxSize(10,10);
  1134.  
  1135.     m_stretchable = 0;
  1136.     m_minWidth = 0;
  1137.     m_minHeight = 0;
  1138.     m_fixedWidth = 0;
  1139.     m_fixedHeight = 0;
  1140.  
  1141.     // Find how long each stretch unit needs to be
  1142.     int stretchSize = 1;
  1143.     wxNode *node = m_children.GetFirst();
  1144.     while (node)
  1145.     {
  1146.         wxSizerItem *item = (wxSizerItem*) node->Data();
  1147.         if (item->IsShown() && item->GetOption() != 0)
  1148.         {
  1149.             int stretch = item->GetOption();
  1150.             wxSize size( item->CalcMin() );
  1151.             int sizePerStretch;
  1152.             // Integer division rounded up is (a + b - 1) / b
  1153.             if (m_orient == wxHORIZONTAL)
  1154.                 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
  1155.             else
  1156.                 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
  1157.             if (sizePerStretch > stretchSize)
  1158.                 stretchSize = sizePerStretch;
  1159.         }
  1160.         node = node->Next();
  1161.     }
  1162.     // Calculate overall minimum size
  1163.     node = m_children.GetFirst();
  1164.     while (node)
  1165.     {
  1166.         wxSizerItem *item = (wxSizerItem*) node->Data();
  1167.         if (item->IsShown())
  1168.         {
  1169.             m_stretchable += item->GetOption();
  1170.  
  1171.             wxSize size( item->CalcMin() );
  1172.             if (item->GetOption() != 0)
  1173.             {
  1174.                 if (m_orient == wxHORIZONTAL)
  1175.                     size.x = stretchSize * item->GetOption();
  1176.                 else
  1177.                     size.y = stretchSize * item->GetOption();
  1178.             }
  1179.  
  1180.             if (m_orient == wxHORIZONTAL)
  1181.             {
  1182.                 m_minWidth += size.x;
  1183.                 m_minHeight = wxMax( m_minHeight, size.y );
  1184.             }
  1185.             else
  1186.             {
  1187.                 m_minHeight += size.y;
  1188.                 m_minWidth = wxMax( m_minWidth, size.x );
  1189.             }
  1190.  
  1191.             if (item->GetOption() == 0)
  1192.             {
  1193.                 if (m_orient == wxVERTICAL)
  1194.                 {
  1195.                     m_fixedHeight += size.y;
  1196.                     m_fixedWidth = wxMax( m_fixedWidth, size.x );
  1197.                 }
  1198.                 else
  1199.                 {
  1200.                     m_fixedWidth += size.x;
  1201.                     m_fixedHeight = wxMax( m_fixedHeight, size.y );
  1202.                 }
  1203.             }
  1204.         }
  1205.         node = node->Next();
  1206.     }
  1207.  
  1208.     return wxSize( m_minWidth, m_minHeight );
  1209. }
  1210.  
  1211. //---------------------------------------------------------------------------
  1212. // wxStaticBoxSizer
  1213. //---------------------------------------------------------------------------
  1214.  
  1215. #if wxUSE_STATBOX
  1216.  
  1217. wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
  1218.                 : wxBoxSizer( orient )
  1219. {
  1220.     wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
  1221.  
  1222.     m_staticBox = box;
  1223. }
  1224.  
  1225. static void GetStaticBoxBorders(wxStaticBox *box,
  1226.                                 int *borderTop, int *borderOther)
  1227. {
  1228.     // this has to be done platform by platform as there is no way to
  1229.     // guess the thickness of a wxStaticBox border
  1230. #ifdef __WXGTK__
  1231.     if ( box->GetLabel().IsEmpty() )
  1232.         *borderTop = 5;
  1233.     else
  1234. #endif // __WXGTK__
  1235.         *borderTop = 15;
  1236.     (void)box;
  1237.     *borderOther = 5;
  1238. }
  1239.  
  1240. void wxStaticBoxSizer::RecalcSizes()
  1241. {
  1242.     int top_border, other_border;
  1243.     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
  1244.  
  1245.     m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
  1246.  
  1247.     wxPoint old_pos( m_position );
  1248.     m_position.x += other_border;
  1249.     m_position.y += top_border;
  1250.     wxSize old_size( m_size );
  1251.     m_size.x -= 2*other_border;
  1252.     m_size.y -= top_border + other_border;
  1253.  
  1254.     wxBoxSizer::RecalcSizes();
  1255.  
  1256.     m_position = old_pos;
  1257.     m_size = old_size;
  1258. }
  1259.  
  1260. wxSize wxStaticBoxSizer::CalcMin()
  1261. {
  1262.     int top_border, other_border;
  1263.     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
  1264.  
  1265.     wxSize ret( wxBoxSizer::CalcMin() );
  1266.     ret.x += 2*other_border;
  1267.     ret.y += other_border + top_border;
  1268.  
  1269.     return ret;
  1270. }
  1271.  
  1272. #endif // wxUSE_STATBOX
  1273.  
  1274. //---------------------------------------------------------------------------
  1275. // wxNotebookSizer
  1276. //---------------------------------------------------------------------------
  1277.  
  1278. #if wxUSE_NOTEBOOK
  1279.  
  1280. wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
  1281. {
  1282.     wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
  1283.  
  1284.     m_notebook = nb;
  1285. }
  1286.  
  1287. void wxNotebookSizer::RecalcSizes()
  1288. {
  1289.     m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
  1290. }
  1291.  
  1292. wxSize wxNotebookSizer::CalcMin()
  1293. {
  1294.     wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
  1295.  
  1296.     sizeBorder.x += 5;
  1297.     sizeBorder.y += 5;
  1298.  
  1299.     if (m_notebook->GetChildren().GetCount() == 0)
  1300.     {
  1301.         return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
  1302.     }
  1303.  
  1304.     int maxX = 0;
  1305.     int maxY = 0;
  1306.  
  1307.     wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
  1308.     while (node)
  1309.     {
  1310.         wxWindow *item = node->GetData();
  1311.         wxSizer *itemsizer = item->GetSizer();
  1312.  
  1313.         if (itemsizer)
  1314.         {
  1315.             wxSize subsize( itemsizer->CalcMin() );
  1316.  
  1317.             if (subsize.x > maxX)
  1318.                 maxX = subsize.x;
  1319.             if (subsize.y > maxY)
  1320.                 maxY = subsize.y;
  1321.         }
  1322.  
  1323.         node = node->GetNext();
  1324.     }
  1325.  
  1326.     return wxSize( maxX, maxY ) + sizeBorder;
  1327. }
  1328.  
  1329. #endif // wxUSE_NOTEBOOK
  1330.  
  1331. // vi:sts=4:sw=4:et
  1332.