/////////////////////////////////////////////////////////////////////////////
// Name:        src/common/sizer.cpp
// Purpose:     provide new wxSizer class for layout
// Author:      Robert Roebling and Robin Dunn, contributions by
//              Dirk Holtwick, Ron Lee
// Modified by: Ron Lee
// Created:
// RCS-ID:      $Id$
// Copyright:   (c) Robin Dunn, Robert Roebling
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#include "wx/sizer.h"
#include "wx/private/flagscheck.h"

#ifndef WX_PRECOMP
    #include "wx/string.h"
    #include "wx/intl.h"
    #include "wx/math.h"
    #include "wx/utils.h"
    #include "wx/settings.h"
    #include "wx/button.h"
    #include "wx/statbox.h"
    #include "wx/toplevel.h"
#endif // WX_PRECOMP

#include "wx/display.h"
#include "wx/vector.h"
#include "wx/listimpl.cpp"


//---------------------------------------------------------------------------

IMPLEMENT_CLASS(wxSizerItem, wxObject)
IMPLEMENT_CLASS(wxSizer, wxObject)
IMPLEMENT_CLASS(wxGridSizer, wxSizer)
IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
#if wxUSE_STATBOX
IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
#endif
#if wxUSE_BUTTON
IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
#endif

WX_DEFINE_EXPORTED_LIST( wxSizerItemList )

/*
    TODO PROPERTIES
      sizeritem
        object
        object_ref
          minsize
          option
          flag
          border
     spacer
        option
        flag
        borfder
    boxsizer
       orient
    staticboxsizer
       orient
       label
    gridsizer
       rows
       cols
       vgap
       hgap
    flexgridsizer
       rows
       cols
       vgap
       hgap
       growablerows
       growablecols
    minsize
*/

// ----------------------------------------------------------------------------
// wxSizerItem
// ----------------------------------------------------------------------------

// check for flags conflicts
static const int SIZER_FLAGS_MASK =
    wxADD_FLAG(wxCENTRE,
    wxADD_FLAG(wxHORIZONTAL,
    wxADD_FLAG(wxVERTICAL,
    wxADD_FLAG(wxLEFT,
    wxADD_FLAG(wxRIGHT,
    wxADD_FLAG(wxUP,
    wxADD_FLAG(wxDOWN,
    wxADD_FLAG(wxALIGN_NOT,
    wxADD_FLAG(wxALIGN_CENTER_HORIZONTAL,
    wxADD_FLAG(wxALIGN_RIGHT,
    wxADD_FLAG(wxALIGN_BOTTOM,
    wxADD_FLAG(wxALIGN_CENTER_VERTICAL,
    wxADD_FLAG(wxFIXED_MINSIZE,
    wxADD_FLAG(wxRESERVE_SPACE_EVEN_IF_HIDDEN,
    wxADD_FLAG(wxSTRETCH_NOT,
    wxADD_FLAG(wxSHRINK,
    wxADD_FLAG(wxGROW,
    wxADD_FLAG(wxSHAPED,
    0))))))))))))))))));

#define ASSERT_VALID_SIZER_FLAGS(f)  wxASSERT_VALID_FLAGS(f, SIZER_FLAGS_MASK)


void wxSizerItem::Init(const wxSizerFlags& flags)
{
    Init();

    m_proportion = flags.GetProportion();
    m_flag = flags.GetFlags();
    m_border = flags.GetBorderInPixels();

    ASSERT_VALID_SIZER_FLAGS( m_flag );
}

wxSizerItem::wxSizerItem()
{
    Init();

    m_proportion = 0;
    m_border = 0;
    m_flag = 0;
    m_id = wxID_NONE;
}

// window item
void wxSizerItem::DoSetWindow(wxWindow *window)
{
    wxCHECK_RET( window, wxT("NULL window in wxSizerItem::SetWindow()") );

    m_kind = Item_Window;
    m_window = window;

    // window doesn't become smaller than its initial size, whatever happens
    m_minSize = window->GetSize();

    if ( m_flag & wxFIXED_MINSIZE )
        window->SetMinSize(m_minSize);

    // aspect ratio calculated from initial size
    SetRatio(m_minSize);
}

wxSizerItem::wxSizerItem(wxWindow *window,
                         int proportion,
                         int flag,
                         int border,
                         wxObject* userData)
           : m_kind(Item_None),
             m_proportion(proportion),
             m_border(border),
             m_flag(flag),
             m_id(wxID_NONE),
             m_userData(userData)
{
    ASSERT_VALID_SIZER_FLAGS( m_flag );

    DoSetWindow(window);
}

// sizer item
void wxSizerItem::DoSetSizer(wxSizer *sizer)
{
    m_kind = Item_Sizer;
    m_sizer = sizer;
}

wxSizerItem::wxSizerItem(wxSizer *sizer,
                         int proportion,
                         int flag,
                         int border,
                         wxObject* userData)
           : m_kind(Item_None),
             m_sizer(NULL),
             m_proportion(proportion),
             m_border(border),
             m_flag(flag),
             m_id(wxID_NONE),
             m_ratio(0.0),
             m_userData(userData)
{
    ASSERT_VALID_SIZER_FLAGS( m_flag );

    DoSetSizer(sizer);

    // m_minSize is set later
}

// spacer item
void wxSizerItem::DoSetSpacer(const wxSize& size)
{
    m_kind = Item_Spacer;
    m_spacer = new wxSizerSpacer(size);
    m_minSize = size;
    SetRatio(size);
}

wxSizerItem::wxSizerItem(int width,
                         int height,
                         int proportion,
                         int flag,
                         int border,
                         wxObject* userData)
           : m_kind(Item_None),
             m_sizer(NULL),
             m_minSize(width, height), // minimal size is the initial size
             m_proportion(proportion),
             m_border(border),
             m_flag(flag),
             m_id(wxID_NONE),
             m_userData(userData)
{
    ASSERT_VALID_SIZER_FLAGS( m_flag );

    DoSetSpacer(wxSize(width, height));
}

wxSizerItem::~wxSizerItem()
{
    delete m_userData;
    Free();
}

void wxSizerItem::Free()
{
    switch ( m_kind )
    {
        case Item_None:
            break;

        case Item_Window:
            m_window->SetContainingSizer(NULL);
            break;

        case Item_Sizer:
            delete m_sizer;
            break;

        case Item_Spacer:
            delete m_spacer;
            break;

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }

    m_kind = Item_None;
}

wxSize wxSizerItem::GetSpacer() const
{
    wxSize size;
    if ( m_kind == Item_Spacer )
        size = m_spacer->GetSize();

    return size;
}


wxSize wxSizerItem::GetSize() const
{
    wxSize ret;
    switch ( m_kind )
    {
        case Item_None:
            break;

        case Item_Window:
            ret = m_window->GetSize();
            break;

        case Item_Sizer:
            ret = m_sizer->GetSize();
            break;

        case Item_Spacer:
            ret = m_spacer->GetSize();
            break;

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }

    if (m_flag & wxWEST)
        ret.x += m_border;
    if (m_flag & wxEAST)
        ret.x += m_border;
    if (m_flag & wxNORTH)
        ret.y += m_border;
    if (m_flag & wxSOUTH)
        ret.y += m_border;

    return ret;
}

bool wxSizerItem::InformFirstDirection(int direction, int size, int availableOtherDir)
{
    // The size that come here will be including borders. Child items should get it
    // without borders.
    if( size>0 )
    {
        if( direction==wxHORIZONTAL )
        {
            if (m_flag & wxWEST)
                size -= m_border;
            if (m_flag & wxEAST)
                size -= m_border;
        }
        else if( direction==wxVERTICAL )
        {
            if (m_flag & wxNORTH)
                size -= m_border;
            if (m_flag & wxSOUTH)
                size -= m_border;
        }
    }

    bool didUse = false;
    // Pass the information along to the held object
    if (IsSizer())
    {
        didUse = GetSizer()->InformFirstDirection(direction,size,availableOtherDir);
        if (didUse)
            m_minSize = GetSizer()->CalcMin();
    }
    else if (IsWindow())
    {
        didUse =  GetWindow()->InformFirstDirection(direction,size,availableOtherDir);
        if (didUse)
            m_minSize = m_window->GetEffectiveMinSize();

        // This information is useful for items with wxSHAPED flag, since
        // we can request an optimal min size for such an item. Even if
        // we overwrite the m_minSize member here, we can read it back from
        // the owned window (happens automatically).
        if( (m_flag & wxSHAPED) && (m_flag & wxEXPAND) && direction )
        {
            if( !wxIsNullDouble(m_ratio) )
            {
                wxCHECK_MSG( (m_proportion==0), false, wxT("Shaped item, non-zero proportion in wxSizerItem::InformFirstDirection()") );
                if( direction==wxHORIZONTAL && !wxIsNullDouble(m_ratio) )
                {
                    // Clip size so that we don't take too much
                    if( availableOtherDir>=0 && int(size/m_ratio)-m_minSize.y>availableOtherDir )
                        size = int((availableOtherDir+m_minSize.y)*m_ratio);
                    m_minSize = wxSize(size,int(size/m_ratio));
                }
                else if( direction==wxVERTICAL )
                {
                    // Clip size so that we don't take too much
                    if( availableOtherDir>=0 && int(size*m_ratio)-m_minSize.x>availableOtherDir )
                        size = int((availableOtherDir+m_minSize.x)/m_ratio);
                    m_minSize = wxSize(int(size*m_ratio),size);
                }
                didUse = true;
            }
        }
    }

    return didUse;
}

wxSize wxSizerItem::CalcMin()
{
    if (IsSizer())
    {
        m_minSize = m_sizer->GetMinSize();

        // if we have to preserve aspect ratio _AND_ this is
        // the first-time calculation, consider ret to be initial size
        if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
            SetRatio(m_minSize);
    }
    else if ( IsWindow() )
    {
        // Since the size of the window may change during runtime, we
        // should use the current minimal/best size.
        m_minSize = m_window->GetEffectiveMinSize();
    }

    return GetMinSizeWithBorder();
}

wxSize wxSizerItem::GetMinSizeWithBorder() const
{
    wxSize ret = m_minSize;

    if (m_flag & wxWEST)
        ret.x += m_border;
    if (m_flag & wxEAST)
        ret.x += m_border;
    if (m_flag & wxNORTH)
        ret.y += m_border;
    if (m_flag & wxSOUTH)
        ret.y += m_border;

    return ret;
}


void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
{
    wxPoint pos = pos_;
    wxSize size = size_;
    if (m_flag & wxSHAPED)
    {
        // adjust aspect ratio
        int rwidth = (int) (size.y * m_ratio);
        if (rwidth > size.x)
        {
            // fit horizontally
            int rheight = (int) (size.x / m_ratio);
            // add vertical space
            if (m_flag & wxALIGN_CENTER_VERTICAL)
                pos.y += (size.y - rheight) / 2;
            else if (m_flag & wxALIGN_BOTTOM)
                pos.y += (size.y - rheight);
            // use reduced dimensions
            size.y =rheight;
        }
        else if (rwidth < size.x)
        {
            // add horizontal space
            if (m_flag & wxALIGN_CENTER_HORIZONTAL)
                pos.x += (size.x - rwidth) / 2;
            else if (m_flag & wxALIGN_RIGHT)
                pos.x += (size.x - rwidth);
            size.x = rwidth;
        }
    }

    // This is what GetPosition() returns. Since we calculate
    // borders afterwards, GetPosition() will be the left/top
    // corner of the surrounding border.
    m_pos = pos;

    if (m_flag & wxWEST)
    {
        pos.x += m_border;
        size.x -= m_border;
    }
    if (m_flag & wxEAST)
    {
        size.x -= m_border;
    }
    if (m_flag & wxNORTH)
    {
        pos.y += m_border;
        size.y -= m_border;
    }
    if (m_flag & wxSOUTH)
    {
        size.y -= m_border;
    }

    if (size.x < 0)
        size.x = 0;
    if (size.y < 0)
        size.y = 0;

    m_rect = wxRect(pos, size);

    switch ( m_kind )
    {
        case Item_None:
            wxFAIL_MSG( wxT("can't set size of uninitialized sizer item") );
            break;

        case Item_Window:
        {
            // Use wxSIZE_FORCE_EVENT here since a sizer item might
            // have changed alignment or some other property which would
            // not change the size of the window. In such a case, no
            // wxSizeEvent would normally be generated and thus the
            // control wouldn't get layed out correctly here.
#if 1
            m_window->SetSize(pos.x, pos.y, size.x, size.y,
                              wxSIZE_ALLOW_MINUS_ONE|wxSIZE_FORCE_EVENT );
#else
            m_window->SetSize(pos.x, pos.y, size.x, size.y,
                              wxSIZE_ALLOW_MINUS_ONE );
#endif
            break;
        }
        case Item_Sizer:
            m_sizer->SetDimension(pos, size);
            break;

        case Item_Spacer:
            m_spacer->SetSize(size);
            break;

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }
}

void wxSizerItem::DeleteWindows()
{
    switch ( m_kind )
    {
        case Item_None:
        case Item_Spacer:
            break;

        case Item_Window:
            //We are deleting the window from this sizer - normally
            //the window destroys the sizer associated with it,
            //which might destroy this, which we don't want
            m_window->SetContainingSizer(NULL);
            m_window->Destroy();
            //Putting this after the switch will result in a spacer
            //not being deleted properly on destruction
            m_kind = Item_None;
            break;

        case Item_Sizer:
            m_sizer->DeleteWindows();
            break;

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }

}

void wxSizerItem::Show( bool show )
{
    switch ( m_kind )
    {
        case Item_None:
            wxFAIL_MSG( wxT("can't show uninitialized sizer item") );
            break;

        case Item_Window:
            m_window->Show(show);
            break;

        case Item_Sizer:
            m_sizer->Show(show);
            break;

        case Item_Spacer:
            m_spacer->Show(show);
            break;

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }
}

bool wxSizerItem::IsShown() const
{
    if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN )
        return true;

    switch ( m_kind )
    {
        case Item_None:
            // we may be called from CalcMin(), just return false so that we're
            // not used
            break;

        case Item_Window:
            return m_window->IsShown();

        case Item_Sizer:
        {
            // arbitrarily decide that if at least one of our elements is
            // shown, so are we (this arbitrariness is the reason for
            // deprecating this function)
            for ( wxSizerItemList::compatibility_iterator
                    node = m_sizer->GetChildren().GetFirst();
                  node;
                  node = node->GetNext() )
            {
                if ( node->GetData()->IsShown() )
                    return true;
            }
            return false;
        }

        case Item_Spacer:
            return m_spacer->IsShown();

        case Item_Max:
        default:
            wxFAIL_MSG( wxT("unexpected wxSizerItem::m_kind") );
    }

    return false;
}

#if WXWIN_COMPATIBILITY_2_6
void wxSizerItem::SetOption( int option )
{
    SetProportion( option );
}

int wxSizerItem::GetOption() const
{
    return GetProportion();
}
#endif // WXWIN_COMPATIBILITY_2_6


//---------------------------------------------------------------------------
// wxSizer
//---------------------------------------------------------------------------

wxSizer::~wxSizer()
{
    WX_CLEAR_LIST(wxSizerItemList, m_children);
}

wxSizerItem* wxSizer::DoInsert( size_t index, wxSizerItem *item )
{
    m_children.Insert( index, item );

    if ( item->GetWindow() )
        item->GetWindow()->SetContainingSizer( this );

    if ( item->GetSizer() )
        item->GetSizer()->SetContainingWindow( m_containingWindow );

    return item;
}

void wxSizer::SetContainingWindow(wxWindow *win)
{
    if ( win == m_containingWindow )
        return;

    m_containingWindow = win;

    // set the same window for all nested sizers as well, they also are in the
    // same window
    for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
          node;
          node = node->GetNext() )
    {
        wxSizerItem *const item = node->GetData();
        wxSizer *const sizer = item->GetSizer();

        if ( sizer )
        {
            sizer->SetContainingWindow(win);
        }
    }
}

#if WXWIN_COMPATIBILITY_2_6
bool wxSizer::Remove( wxWindow *window )
{
    return Detach( window );
}
#endif // WXWIN_COMPATIBILITY_2_6

bool wxSizer::Remove( wxSizer *sizer )
{
    wxASSERT_MSG( sizer, wxT("Removing NULL sizer") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetSizer() == sizer)
        {
            delete item;
            m_children.Erase( node );
            return true;
        }

        node = node->GetNext();
    }

    return false;
}

bool wxSizer::Remove( int index )
{
    wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
                 false,
                 wxT("Remove index is out of range") );

    wxSizerItemList::compatibility_iterator node = m_children.Item( index );

    wxCHECK_MSG( node, false, wxT("Failed to find child node") );

    delete node->GetData();
    m_children.Erase( node );

    return true;
}

bool wxSizer::Detach( wxSizer *sizer )
{
    wxASSERT_MSG( sizer, wxT("Detaching NULL sizer") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetSizer() == sizer)
        {
            item->DetachSizer();
            delete item;
            m_children.Erase( node );
            return true;
        }
        node = node->GetNext();
    }

    return false;
}

bool wxSizer::Detach( wxWindow *window )
{
    wxASSERT_MSG( window, wxT("Detaching NULL window") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetWindow() == window)
        {
            delete item;
            m_children.Erase( node );
            return true;
        }
        node = node->GetNext();
    }

    return false;
}

bool wxSizer::Detach( int index )
{
    wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
                 false,
                 wxT("Detach index is out of range") );

    wxSizerItemList::compatibility_iterator node = m_children.Item( index );

    wxCHECK_MSG( node, false, wxT("Failed to find child node") );

    wxSizerItem *item = node->GetData();

    if ( item->IsSizer() )
        item->DetachSizer();

    delete item;
    m_children.Erase( node );
    return true;
}

bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
{
    wxASSERT_MSG( oldwin, wxT("Replacing NULL window") );
    wxASSERT_MSG( newwin, wxT("Replacing with NULL window") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetWindow() == oldwin)
        {
            item->AssignWindow(newwin);
            newwin->SetContainingSizer( this );
            return true;
        }
        else if (recursive && item->IsSizer())
        {
            if (item->GetSizer()->Replace( oldwin, newwin, true ))
                return true;
        }

        node = node->GetNext();
    }

    return false;
}

bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive )
{
    wxASSERT_MSG( oldsz, wxT("Replacing NULL sizer") );
    wxASSERT_MSG( newsz, wxT("Replacing with NULL sizer") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetSizer() == oldsz)
        {
            item->AssignSizer(newsz);
            return true;
        }
        else if (recursive && item->IsSizer())
        {
            if (item->GetSizer()->Replace( oldsz, newsz, true ))
                return true;
        }

        node = node->GetNext();
    }

    return false;
}

bool wxSizer::Replace( size_t old, wxSizerItem *newitem )
{
    wxCHECK_MSG( old < m_children.GetCount(), false, wxT("Replace index is out of range") );
    wxASSERT_MSG( newitem, wxT("Replacing with NULL item") );

    wxSizerItemList::compatibility_iterator node = m_children.Item( old );

    wxCHECK_MSG( node, false, wxT("Failed to find child node") );

    wxSizerItem *item = node->GetData();
    node->SetData(newitem);

    if (item->IsWindow() && item->GetWindow())
        item->GetWindow()->SetContainingSizer(NULL);

    delete item;

    return true;
}

void wxSizer::Clear( bool delete_windows )
{
    // First clear the ContainingSizer pointers
    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->IsWindow())
            item->GetWindow()->SetContainingSizer( NULL );
        node = node->GetNext();
    }

    // Destroy the windows if needed
    if (delete_windows)
        DeleteWindows();

    // Now empty the list
    WX_CLEAR_LIST(wxSizerItemList, m_children);
}

void wxSizer::DeleteWindows()
{
    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        item->DeleteWindows();
        node = node->GetNext();
    }
}

wxSize wxSizer::ComputeFittingClientSize(wxWindow *window)
{
    wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );

    // take the min size by default and limit it by max size
    wxSize size = GetMinClientSize(window);
    wxSize sizeMax;

    wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
    if ( tlw )
    {
        // hack for small screen devices where TLWs are always full screen
        if ( tlw->IsAlwaysMaximized() )
        {
            return tlw->GetClientSize();
        }

        // limit the window to the size of the display it is on
        int disp = wxDisplay::GetFromWindow(window);
        if ( disp == wxNOT_FOUND )
        {
            // or, if we don't know which one it is, of the main one
            disp = 0;
        }

        sizeMax = wxDisplay(disp).GetClientArea().GetSize();

        // If determining the display size failed, skip the max size checks as
        // we really don't want to create windows of (0, 0) size.
        if ( !sizeMax.x || !sizeMax.y )
            return size;

        // space for decorations and toolbars etc.
        sizeMax = tlw->WindowToClientSize(sizeMax);
    }
    else
    {
        sizeMax = GetMaxClientSize(window);
    }

    if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
            size.x = sizeMax.x;
    if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
            size.y = sizeMax.y;

    return size;
}

wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window)
{
    wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );

    return window->ClientToWindowSize(ComputeFittingClientSize(window));
}

wxSize wxSizer::Fit( wxWindow *window )
{
    wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );

    // set client size
    window->SetClientSize(ComputeFittingClientSize(window));

    // return entire size
    return window->GetSize();
}

void wxSizer::FitInside( wxWindow *window )
{
    wxSize size;
    if (window->IsTopLevel())
        size = VirtualFitSize( window );
    else
        size = GetMinClientSize( window );

    window->SetVirtualSize( size );
}

void wxSizer::Layout()
{
    // (re)calculates minimums needed for each item and other preparations
    // for layout
    CalcMin();

    // Applies the layout and repositions/resizes the items
    RecalcSizes();
}

void wxSizer::SetSizeHints( wxWindow *window )
{
    // Preserve the window's max size hints, but set the
    // lower bound according to the sizer calculations.

    // This is equivalent to calling Fit(), except that we need to set
    // the size hints _in between_ the two steps performed by Fit
    // (1. ComputeFittingClientSize, 2. SetClientSize). That's because
    // otherwise SetClientSize() could have no effect if there already are
    // size hints in effect that forbid requested client size.

    const wxSize clientSize = ComputeFittingClientSize(window);

    window->SetMinClientSize(clientSize);
    window->SetClientSize(clientSize);
}

#if WXWIN_COMPATIBILITY_2_8
void wxSizer::SetVirtualSizeHints( wxWindow *window )
{
    FitInside( window );
}
#endif // WXWIN_COMPATIBILITY_2_8

// TODO on mac we need a function that determines how much free space this
// min size contains, in order to make sure that we have 20 pixels of free
// space around the controls
wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
{
    return window->WindowToClientSize(window->GetMaxSize());
}

wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
{
    return GetMinSize();  // Already returns client size.
}

wxSize wxSizer::VirtualFitSize( wxWindow *window )
{
    wxSize size     = GetMinClientSize( window );
    wxSize sizeMax  = GetMaxClientSize( window );

    // Limit the size if sizeMax != wxDefaultSize

    if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
        size.x = sizeMax.x;
    if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
        size.y = sizeMax.y;

    return size;
}

wxSize wxSizer::GetMinSize()
{
    wxSize ret( CalcMin() );
    if (ret.x < m_minSize.x) ret.x = m_minSize.x;
    if (ret.y < m_minSize.y) ret.y = m_minSize.y;
    return ret;
}

void wxSizer::DoSetMinSize( int width, int height )
{
    m_minSize.x = width;
    m_minSize.y = height;
}

bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
{
    wxASSERT_MSG( window, wxT("SetMinSize for NULL window") );

    // Is it our immediate child?

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetWindow() == window)
        {
            item->SetMinSize( width, height );
            return true;
        }
        node = node->GetNext();
    }

    // No?  Search any subsizers we own then

    node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if ( item->GetSizer() &&
             item->GetSizer()->DoSetItemMinSize( window, width, height ) )
        {
            // A child sizer found the requested windw, exit.
            return true;
        }
        node = node->GetNext();
    }

    return false;
}

bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
{
    wxASSERT_MSG( sizer, wxT("SetMinSize for NULL sizer") );

    // Is it our immediate child?

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetSizer() == sizer)
        {
            item->GetSizer()->DoSetMinSize( width, height );
            return true;
        }
        node = node->GetNext();
    }

    // No?  Search any subsizers we own then

    node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if ( item->GetSizer() &&
             item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
        {
            // A child found the requested sizer, exit.
            return true;
        }
        node = node->GetNext();
    }

    return false;
}

bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
{
    wxSizerItemList::compatibility_iterator node = m_children.Item( index );

    wxCHECK_MSG( node, false, wxT("Failed to find child node") );

    wxSizerItem     *item = node->GetData();

    if (item->GetSizer())
    {
        // Sizers contains the minimal size in them, if not calculated ...
        item->GetSizer()->DoSetMinSize( width, height );
    }
    else
    {
        // ... but the minimal size of spacers and windows is stored via the item
        item->SetMinSize( width, height );
    }

    return true;
}

wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
{
    wxASSERT_MSG( window, wxT("GetItem for NULL window") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetWindow() == window)
        {
            return item;
        }
        else if (recursive && item->IsSizer())
        {
            wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
            if (subitem)
                return subitem;
        }

        node = node->GetNext();
    }

    return NULL;
}

wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
{
    wxASSERT_MSG( sizer, wxT("GetItem for NULL sizer") );

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem *item = node->GetData();

        if (item->GetSizer() == sizer)
        {
            return item;
        }
        else if (recursive && item->IsSizer())
        {
            wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
            if (subitem)
                return subitem;
        }

        node = node->GetNext();
    }

    return NULL;
}

wxSizerItem* wxSizer::GetItem( size_t index )
{
    wxCHECK_MSG( index < m_children.GetCount(),
                 NULL,
                 wxT("GetItem index is out of range") );

    return m_children.Item( index )->GetData();
}

wxSizerItem* wxSizer::GetItemById( int id, bool recursive )
{
    // This gets a sizer item by the id of the sizer item
    // and NOT the id of a window if the item is a window.

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetId() == id)
        {
            return item;
        }
        else if (recursive && item->IsSizer())
        {
            wxSizerItem *subitem = item->GetSizer()->GetItemById( id, true );
            if (subitem)
                return subitem;
        }

        node = node->GetNext();
    }

    return NULL;
}

bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
{
    wxSizerItem *item = GetItem( window, recursive );

    if ( item )
    {
         item->Show( show );
         return true;
    }

    return false;
}

bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
{
    wxSizerItem *item = GetItem( sizer, recursive );

    if ( item )
    {
         item->Show( show );
         return true;
    }

    return false;
}

bool wxSizer::Show( size_t index, bool show)
{
    wxSizerItem *item = GetItem( index );

    if ( item )
    {
         item->Show( show );
         return true;
    }

    return false;
}

void wxSizer::ShowItems( bool show )
{
    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        node->GetData()->Show( show );
        node = node->GetNext();
    }
}

bool wxSizer::IsShown( wxWindow *window ) const
{
    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetWindow() == window)
        {
            return item->IsShown();
        }
        node = node->GetNext();
    }

    wxFAIL_MSG( wxT("IsShown failed to find sizer item") );

    return false;
}

bool wxSizer::IsShown( wxSizer *sizer ) const
{
    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();

        if (item->GetSizer() == sizer)
        {
            return item->IsShown();
        }
        node = node->GetNext();
    }

    wxFAIL_MSG( wxT("IsShown failed to find sizer item") );

    return false;
}

bool wxSizer::IsShown( size_t index ) const
{
    wxCHECK_MSG( index < m_children.GetCount(),
                 false,
                 wxT("IsShown index is out of range") );

    return m_children.Item( index )->GetData()->IsShown();
}


//---------------------------------------------------------------------------
// wxGridSizer
//---------------------------------------------------------------------------

wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
    : m_rows( cols == 0 ? 1 : 0 ),
      m_cols( cols ),
      m_vgap( vgap ),
      m_hgap( hgap )
{
    wxASSERT(cols >= 0);
}

wxGridSizer::wxGridSizer( int cols, const wxSize& gap )
    : m_rows( cols == 0 ? 1 : 0 ),
      m_cols( cols ),
      m_vgap( gap.GetHeight() ),
      m_hgap( gap.GetWidth() )
{
    wxASSERT(cols >= 0);
}

wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
    : m_rows( rows || cols ? rows : 1 ),
      m_cols( cols ),
      m_vgap( vgap ),
      m_hgap( hgap )
{
    wxASSERT(rows >= 0 && cols >= 0);
}

wxGridSizer::wxGridSizer( int rows, int cols, const wxSize& gap )
    : m_rows( rows || cols ? rows : 1 ),
      m_cols( cols ),
      m_vgap( gap.GetHeight() ),
      m_hgap( gap.GetWidth() )
{
    wxASSERT(rows >= 0 && cols >= 0);
}

wxSizerItem *wxGridSizer::DoInsert(size_t index, wxSizerItem *item)
{
    // if only the number of columns or the number of rows is specified for a
    // sizer, arbitrarily many items can be added to it but if both of them are
    // fixed, then the sizer can't have more than that many items -- check for
    // this here to ensure that we detect errors as soon as possible
    if ( m_cols && m_rows )
    {
        const int nitems = m_children.GetCount();
        if ( nitems == m_cols*m_rows )
        {
            wxFAIL_MSG(
                wxString::Format(
                    "too many items (%d > %d*%d) in grid sizer (maybe you "
                    "should omit the number of either rows or columns?)",
                nitems + 1, m_cols, m_rows)
            );

            // additionally, continuing to use the specified number of columns
            // and rows is not a good idea as callers of CalcRowsCols() expect
            // that all sizer items can fit into m_cols-/m_rows-sized arrays
            // which is not the case if there are too many items and results in
            // crashes, so let it compute the number of rows automatically by
            // forgetting the (wrong) number of rows specified (this also has a
            // nice side effect of giving only one assert even if there are
            // many more items than allowed in this sizer)
            m_rows = 0;
        }
    }

    return wxSizer::DoInsert(index, item);
}

int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
{
    const int nitems = m_children.GetCount();

    ncols = GetEffectiveColsCount();
    nrows = GetEffectiveRowsCount();

    // Since Insert() checks for overpopulation, the following
    // should only assert if the grid was shrunk via SetRows() / SetCols()
    wxASSERT_MSG( nitems <= ncols*nrows, "logic error in wxGridSizer" );

    return nitems;
}

void wxGridSizer::RecalcSizes()
{
    int nitems, nrows, ncols;
    if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
        return;

    wxSize sz( GetSize() );
    wxPoint pt( GetPosition() );

    int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
    int h = (sz.y - (nrows - 1) * m_vgap) / nrows;

    int x = pt.x;
    for (int c = 0; c < ncols; c++)
    {
        int y = pt.y;
        for (int r = 0; r < nrows; r++)
        {
            int i = r * ncols + c;
            if (i < nitems)
            {
                wxSizerItemList::compatibility_iterator node = m_children.Item( i );

                wxASSERT_MSG( node, wxT("Failed to find SizerItemList node") );

                SetItemBounds( node->GetData(), x, y, w, h);
            }
            y = y + h + m_vgap;
        }
        x = x + w + m_hgap;
    }
}

wxSize wxGridSizer::CalcMin()
{
    int nrows, ncols;
    if ( CalcRowsCols(nrows, ncols) == 0 )
        return wxSize();

    // Find the max width and height for any component
    int w = 0;
    int h = 0;

    wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
    while (node)
    {
        wxSizerItem     *item = node->GetData();
        wxSize           sz( item->CalcMin() );

        w = wxMax( w, sz.x );
        h = wxMax( h, sz.y );

        node = node->GetNext();
    }

    // In case we have a nested sizer with a two step algo , give it
    // a chance to adjust to that (we give it width component)
    node = m_children.GetFirst();
    bool didChangeMinSize = false;
    while (node)
    {
        wxSizerItem     *item = node->GetData();
        didChangeMinSize |= item->InformFirstDirection( wxHORIZONTAL, w, -1 );

        node = node->GetNext();
    }

    // And redo iteration in case min size changed
    if( didChangeMinSize )
    {
        node = m_children.GetFirst();
        w = h = 0;
        while (node)
        {
            wxSizerItem     *item = node->GetData();
            wxSize           sz( item->GetMinSizeWithBorder() );

            w = wxMax( w, sz.x );
            h = wxMax( h, sz.y );

            node = node->GetNext();
        }
    }

    return wxSize( ncols * w + (ncols-1) * m_hgap,
                   nrows * h + (nrows-1) * m_vgap );
}

void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
{
    wxPoint pt( x,y );
    wxSize sz( item->GetMinSizeWithBorder() );
    int flag = item->GetFlag();

    if ((flag & wxEXPAND) || (flag & wxSHAPED))
    {
       sz = wxSize(w, h);
    }
    else
    {
        if (flag & wxALIGN_CENTER_HORIZONTAL)
        {
            pt.x = x + (w - sz.x) / 2;
        }
        else if (flag & wxALIGN_RIGHT)
        {
            pt.x = x + (w - sz.x);
        }

        if (flag & wxALIGN_CENTER_VERTICAL)
        {
            pt.y = y + (h - sz.y) / 2;
        }
        else if (flag & wxALIGN_BOTTOM)
        {
            pt.y = y + (h - sz.y);
        }
    }

    item->SetDimension(pt, sz);
}

//---------------------------------------------------------------------------
// wxFlexGridSizer
//---------------------------------------------------------------------------

wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
               : wxGridSizer( cols, vgap, hgap ),
                 m_flexDirection(wxBOTH),
                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
{
}

wxFlexGridSizer::wxFlexGridSizer( int cols, const wxSize& gap )
               : wxGridSizer( cols, gap ),
                 m_flexDirection(wxBOTH),
                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
{
}

wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
               : wxGridSizer( rows, cols, vgap, hgap ),
                 m_flexDirection(wxBOTH),
                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
{
}

wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, const wxSize& gap )
               : wxGridSizer( rows, cols, gap ),
                 m_flexDirection(wxBOTH),
                 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
{
}

wxFlexGridSizer::~wxFlexGridSizer()
{
}

void wxFlexGridSizer::RecalcSizes()
{
    int nrows, ncols;
    if ( !CalcRowsCols(nrows, ncols) )
        return;

    const wxPoint pt(GetPosition());
    const wxSize sz(GetSize());

    AdjustForGrowables(sz);

    wxSizerItemList::const_iterator i = m_children.begin();
    const wxSizerItemList::const_iterator end = m_children.end();

    int y = 0;
    for ( int r = 0; r < nrows; r++ )
    {
        if ( m_rowHeights[r] == -1 )
        {
            // this row is entirely hidden, skip it
            for ( int c = 0; c < ncols; c++ )
            {
                if ( i == end )
                    return;

                ++i;
            }

            continue;
        }

        const int hrow = m_rowHeights[r];
        int h = sz.y - y; // max remaining height, don't overflow it
        if ( hrow < h )
            h = hrow;

        int x = 0;
        for ( int c = 0; c < ncols && i != end; c++, ++i )
        {
            const int wcol = m_colWidths[c];

            if ( wcol == -1 )
                continue;

            int w = sz.x - x; // max possible value, ensure we don't overflow
            if ( wcol < w )
                w = wcol;

            SetItemBounds(*i, pt.x + x, pt.y + y, w, h);

            x += wcol + m_hgap;
        }

        if ( i == end )
            return;

        y += hrow + m_vgap;
    }
}

// helper function used in CalcMin() to sum up the sizes of non-hidden items
static int SumArraySizes(const wxArrayInt& sizes, int gap)
{
    // Sum total minimum size, including gaps between rows/columns.
    // -1 is used as a magic number meaning empty row/column.
    int total = 0;

    const size_t count = sizes.size();
    for ( size_t n = 0; n < count; n++ )
    {
        if ( sizes[n] != -1 )
        {
            if ( total )
                total += gap; // separate from the previous column

            total += sizes[n];
        }
    }

    return total;
}

void wxFlexGridSizer::FindWidthsAndHeights(int nrows, int ncols)
{
    // We have to recalculate the sizes in case the item minimum size has
    // changed since the previous layout, or the item has been hidden using
    // wxSizer::Show(). If all the items in a row/column are hidden, the final
    // dimension of the row/column will be -1, indicating that the column
    // itself is hidden.
    m_rowHeights.assign(nrows, -1);
    m_colWidths.assign(ncols, -1);

    // n is the index of the item in left-to-right top-to-bottom order
    size_t n = 0;
    for ( wxSizerItemList::iterator i = m_children.begin();
          i != m_children.end();
          ++i, ++n )
    {
        wxSizerItem * const item = *i;
        if ( item->IsShown() )
        {
            // NOTE: Not doing the calculation here, this is just
            // for finding max values.
            const wxSize sz(item->GetMinSizeWithBorder());

            const int row = n / ncols;
            const int col = n % ncols;

            if ( sz.y > m_rowHeights[row] )
                m_rowHeights[row] = sz.y;
            if ( sz.x > m_colWidths[col] )
                m_colWidths[col] = sz.x;
        }
    }

    AdjustForFlexDirection();

    m_calculatedMinSize = wxSize(SumArraySizes(m_colWidths, m_hgap),
                                 SumArraySizes(m_rowHeights, m_vgap));
}

wxSize wxFlexGridSizer::CalcMin()
{
    int nrows,
        ncols;

    // Number of rows/columns can change as items are added or removed.
    if ( !CalcRowsCols(nrows, ncols) )
        return wxSize();


    // We have to recalculate the sizes in case the item minimum size has
    // changed since the previous layout, or the item has been hidden using
    // wxSizer::Show(). If all the items in a row/column are hidden, the final
    // dimension of the row/column will be -1, indicating that the column
    // itself is hidden.
    m_rowHeights.assign(nrows, -1);
    m_colWidths.assign(ncols, -1);

    for ( wxSizerItemList::iterator i = m_children.begin();
          i != m_children.end();
          ++i)
    {
        wxSizerItem * const item = *i;
        if ( item->IsShown() )
        {
            item->CalcMin();
        }
    }

    // The stage of looking for max values in each row/column has been
    // made a separate function, since it's reused in AdjustForGrowables.
    FindWidthsAndHeights(nrows,ncols);

    return m_calculatedMinSize;
}

void wxFlexGridSizer::AdjustForFlexDirection()
{
    // the logic in CalcMin works when we resize flexibly in both directions
    // but maybe this is not the case
    if ( m_flexDirection != wxBOTH )
    {
        // select the array corresponding to the direction in which we do *not*
        // resize flexibly
        wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
                                                          : m_rowHeights;

        const size_t count = array.GetCount();

        // find the largest value in this array
        size_t n;
        int largest = 0;

        for ( n = 0; n < count; ++n )
        {
            if ( array[n] > largest )
                largest = array[n];
        }

        // and now fill it with the largest value
        for ( n = 0; n < count; ++n )
        {
            // don't touch hidden rows
            if ( array[n] != -1 )
                array[n] = largest;
        }
    }
}

// helper of AdjustForGrowables() which is called for rows/columns separately
//
// parameters:
//      delta: the extra space, we do nothing unless it's positive
//      growable: indices or growable rows/cols in sizes array
//      sizes: the height/widths of rows/cols to adjust
//      proportions: proportions of the growable rows/cols or NULL if they all
//                   should be assumed to have proportion of 1
static void
DoAdjustForGrowables(int delta,
                     const wxArrayInt& growable,
                     wxArrayInt& sizes,
                     const wxArrayInt *proportions)
{
    if ( delta <= 0 )
        return;

    // total sum of proportions of all non-hidden rows
    int sum_proportions = 0;

    // number of currently shown growable rows
    int num = 0;

    const int max_idx = sizes.size();

    const size_t count = growable.size();
    size_t idx;
    for ( idx = 0; idx < count; idx++ )
    {
        // Since the number of rows/columns can change as items are
        // inserted/deleted, we need to verify at runtime that the
        // requested growable rows/columns are still valid.
        if ( growable[idx] >= max_idx )
            continue;

        // If all items in a row/column are hidden, that row/column will
        // have a dimension of -1.  This causes the row/column to be
        // hidden completely.
        if ( sizes[growable[idx]] == -1 )
            continue;

        if ( proportions )
            sum_proportions += (*proportions)[idx];

        num++;
    }

    if ( !num )
        return;

    // the remaining extra free space, adjusted during each iteration
    for ( idx = 0; idx < count; idx++ )
    {
        if ( growable[idx] >= max_idx )
            continue;

        if ( sizes[ growable[idx] ] == -1 )
            continue;

        int cur_delta;
        if ( sum_proportions == 0 )
        {
            // no growable rows -- divide extra space evenly among all
            cur_delta = delta/num;
            num--;
        }
        else // allocate extra space proportionally
        {
            const int cur_prop = (*proportions)[idx];
            cur_delta = (delta*cur_prop)/sum_proportions;
            sum_proportions -= cur_prop;
        }

        sizes[growable[idx]] += cur_delta;
        delta -= cur_delta;
    }
}

void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
{
#if wxDEBUG_LEVEL
    // by the time this function is called, the sizer should be already fully
    // initialized and hence the number of its columns and rows is known and we
    // can check that all indices in m_growableCols/Rows are valid (see also
    // comments in AddGrowableCol/Row())
    if ( !m_rows || !m_cols )
    {
        if ( !m_rows )
        {
            int nrows = CalcRows();

            for ( size_t n = 0; n < m_growableRows.size(); n++ )
            {
                wxASSERT_MSG( m_growableRows[n] < nrows,
                              "invalid growable row index" );
            }
        }

        if ( !m_cols )
        {
            int ncols = CalcCols();

            for ( size_t n = 0; n < m_growableCols.size(); n++ )
            {
                wxASSERT_MSG( m_growableCols[n] < ncols,
                              "invalid growable column index" );
            }
        }
    }
#endif // wxDEBUG_LEVEL


    if ( (m_flexDirection & wxHORIZONTAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
    {
        DoAdjustForGrowables
        (
            sz.x - m_calculatedMinSize.x,
            m_growableCols,
            m_colWidths,
            m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
                                                    : NULL
        );

        // This gives nested objects that benefit from knowing one size
        // component in advance the chance to use that.
        bool didAdjustMinSize = false;

        // Iterate over all items and inform about column width
        const int ncols = GetEffectiveColsCount();
        int col = 0;
        for ( wxSizerItemList::iterator i = m_children.begin();
              i != m_children.end();
              ++i )
        {
            didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
            if ( ++col == ncols )
                col = 0;
        }

        // Only redo if info was actually used
        if( didAdjustMinSize )
        {
            DoAdjustForGrowables
            (
                sz.x - m_calculatedMinSize.x,
                m_growableCols,
                m_colWidths,
                m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
                                                        : NULL
            );
        }
    }

    if ( (m_flexDirection & wxVERTICAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
    {
        // pass NULL instead of proportions if the grow mode is ALL as we
        // should treat all rows as having proportion of 1 then
        DoAdjustForGrowables
        (
            sz.y - m_calculatedMinSize.y,
            m_growableRows,
            m_rowHeights,
            m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableRowsProportions
                                                    : NULL
        );
    }
}

bool wxFlexGridSizer::IsRowGrowable( size_t idx )
{
    return m_growableRows.Index( idx ) != wxNOT_FOUND;
}

bool wxFlexGridSizer::IsColGrowable( size_t idx )
{
    return m_growableCols.Index( idx ) != wxNOT_FOUND;
}

void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
{
    wxASSERT_MSG( !IsRowGrowable( idx ),
                  "AddGrowableRow() called for growable row" );

    // notice that we intentionally don't check the index validity here in (the
    // common) case when the number of rows was not specified in the ctor -- in
    // this case it will be computed only later, when all items are added to
    // the sizer, and the check will be done in AdjustForGrowables()
    wxCHECK_RET( !m_rows || idx < (size_t)m_rows, "invalid row index" );

    m_growableRows.Add( idx );
    m_growableRowsProportions.Add( proportion );
}

void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
{
    wxASSERT_MSG( !IsColGrowable( idx ),
                  "AddGrowableCol() called for growable column" );

    // see comment in AddGrowableRow(): although it's less common to omit the
    // specification of the number of columns, it still can also happen
    wxCHECK_RET( !m_cols || idx < (size_t)m_cols, "invalid column index" );

    m_growableCols.Add( idx );
    m_growableColsProportions.Add( proportion );
}

// helper function for RemoveGrowableCol/Row()
static void
DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
{
    const size_t count = items.size();
    for ( size_t n = 0; n < count; n++ )
    {
        if ( (size_t)items[n] == idx )
        {
            items.RemoveAt(n);
            proportions.RemoveAt(n);
            return;
        }
    }

    wxFAIL_MSG( wxT("column/row is already not growable") );
}

void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
{
    DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
}

void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
{
    DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
}

//---------------------------------------------------------------------------
// wxBoxSizer
//---------------------------------------------------------------------------

wxSizerItem *wxBoxSizer::AddSpacer(int size)
{
    return IsVertical() ? Add(0, size) : Add(size, 0);
}

namespace
{

/*
    Helper of RecalcSizes(): checks if there is enough remaining space for the
    min size of the given item and returns its min size or the entire remaining
    space depending on which one is greater.

    This function updates the remaining space parameter to account for the size
    effectively allocated to the item.
 */
int
GetMinOrRemainingSize(int orient, const wxSizerItem *item, int *remainingSpace_)
{
    int& remainingSpace = *remainingSpace_;

    wxCoord size;
    if ( remainingSpace > 0 )
    {
        const wxSize sizeMin = item->GetMinSizeWithBorder();
        size = orient == wxHORIZONTAL ? sizeMin.x : sizeMin.y;

        if ( size >= remainingSpace )
        {
            // truncate the item to fit in the remaining space, this is better
            // than showing it only partially in general, even if both choices
            // are bad -- but there is nothing else we can do
            size = remainingSpace;
        }

        remainingSpace -= size;
    }
    else // no remaining space
    {
        // no space at all left, no need to even query the item for its min
        // size as we can't give it to it anyhow
        size = 0;
    }

    return size;
}

} // anonymous namespace

void wxBoxSizer::RecalcSizes()
{
    if ( m_children.empty() )
        return;

    const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
    const wxCoord totalMajorSize = GetSizeInMajorDir(m_size);

    // the amount of free space which we should redistribute among the
    // stretchable items (i.e. those with non zero proportion)
    int delta = totalMajorSize - GetSizeInMajorDir(m_minSize);

    // declare loop variables used below:
    wxSizerItemList::const_iterator i;  // iterator in m_children list
    unsigned n = 0;                     // item index in majorSizes array


    // First, inform item about the available size in minor direction as this
    // can change their size in the major direction. Also compute the number of
    // visible items and sum of their min sizes in major direction.

    int minMajorSize = 0;
    for ( i = m_children.begin(); i != m_children.end(); ++i )
    {
        wxSizerItem * const item = *i;

        if ( !item->IsShown() )
            continue;

        wxSize szMinPrev = item->GetMinSizeWithBorder();
        item->InformFirstDirection(m_orient^wxBOTH,totalMinorSize,delta);
        wxSize szMin = item->GetMinSizeWithBorder();
        int deltaChange = GetSizeInMajorDir(szMin-szMinPrev);
        if( deltaChange )
        {
            // Since we passed available space along to the item, it should not
            // take too much, so delta should not become negative.
            delta -= deltaChange;
        }
        minMajorSize += GetSizeInMajorDir(item->GetMinSizeWithBorder());
    }

    // update our min size and delta which may have changed
    SizeInMajorDir(m_minSize) = minMajorSize;
    delta = totalMajorSize - minMajorSize;


    // space and sum of proportions for the remaining items, both may change
    // below
    wxCoord remaining = totalMajorSize;
    int totalProportion = m_totalProportion;

    // size of the (visible) items in major direction, -1 means "not fixed yet"
    wxVector<int> majorSizes(GetItemCount(), wxDefaultCoord);


    // Check for the degenerated case when we don't have enough space for even
    // the min sizes of all the items: in this case we really can't do much
    // more than to allocate the min size to as many of fixed size items as
    // possible (on the assumption that variable size items such as text zones
    // or list boxes may use scrollbars to show their content even if their
    // size is less than min size but that fixed size items such as buttons
    // will suffer even more if we don't give them their min size)
    if ( totalMajorSize < minMajorSize )
    {
        // Second degenerated case pass: allocate min size to all fixed size
        // items.
        for ( i = m_children.begin(), n = 0; i != m_children.end(); ++i, ++n )
        {
            wxSizerItem * const item = *i;

            if ( !item->IsShown() )
                continue;

            // deal with fixed size items only during this pass
            if ( item->GetProportion() )
                continue;

            majorSizes[n] = GetMinOrRemainingSize(m_orient, item, &remaining);
        }


        // Third degenerated case pass: allocate min size to all the remaining,
        // i.e. non-fixed size, items.
        for ( i = m_children.begin(), n = 0; i != m_children.end(); ++i, ++n )
        {
            wxSizerItem * const item = *i;

            if ( !item->IsShown() )
                continue;

            // we've already dealt with fixed size items above
            if ( !item->GetProportion() )
                continue;

            majorSizes[n] = GetMinOrRemainingSize(m_orient, item, &remaining);
        }
    }
    else // we do have enough space to give at least min sizes to all items
    {
        // Second and maybe more passes in the non-degenerated case: deal with
        // fixed size items and items whose min size is greater than what we
        // would allocate to them taking their proportion into account. For
        // both of them, we will just use their min size, but for the latter we
        // also need to reexamine all the items as the items which fitted
        // before we adjusted their size upwards might not fit any more. This
        // does make for a quadratic algorithm but it's not obvious how to
        // avoid it and hopefully it's not a huge problem in practice as the
        // sizers don't have many items usually (and, of course, the algorithm
        // still reduces into a linear one if there is enough space for all the
        // min sizes).
        bool nonFixedSpaceChanged = false;
        for ( i = m_children.begin(), n = 0; ; ++i, ++n )
        {
            if ( nonFixedSpaceChanged )
            {
                i = m_children.begin();
                n = 0;
                nonFixedSpaceChanged = false;
            }

            // check for the end of the loop only after the check above as
            // otherwise we wouldn't do another pass if the last child resulted
            // in non fixed space reduction
            if ( i == m_children.end() )
                break;

            wxSizerItem * const item = *i;

            if ( !item->IsShown() )
                continue;

            // don't check the item which we had already dealt with during a
            // previous pass (this is more than an optimization, the code
            // wouldn't work correctly if we kept adjusting for the same item
            // over and over again)
            if ( majorSizes[n] != wxDefaultCoord )
                continue;

            wxCoord minMajor = GetSizeInMajorDir(item->GetMinSizeWithBorder());

            // it doesn't make sense for min size to be negative but right now
            // it's possible to create e.g. a spacer with (-1, 10) as size and
            // people do it in their code apparently (see #11842) so ensure
            // that we don't use this -1 as real min size as it conflicts with
            // the meaning we use for it here and negative min sizes just don't
            // make sense anyhow (which is why it might be a better idea to
            // deal with them at wxSizerItem level in the future but for now
            // this is the minimal fix for the bug)
            if ( minMajor < 0 )
                minMajor = 0;

            const int propItem = item->GetProportion();
            if ( propItem )
            {
                // is the desired size of this item big enough?
                if ( (remaining*propItem)/totalProportion >= minMajor )
                {
                    // yes, it is, we'll determine the real size of this
                    // item later, for now just leave it as wxDefaultCoord
                    continue;
                }

                // the proportion of this item won't count, it has
                // effectively become fixed
                totalProportion -= propItem;
            }

            // we can already allocate space for this item
            majorSizes[n] = minMajor;

            // change the amount of the space remaining to the other items,
            // as this can result in not being able to satisfy their
            // proportions any more we will need to redo another loop
            // iteration
            remaining -= minMajor;

            nonFixedSpaceChanged = true;
        }


        // Last by one pass: distribute the remaining space among the non-fixed
        // items whose size weren't fixed yet according to their proportions.
        for ( i = m_children.begin(), n = 0; i != m_children.end(); ++i, ++n )
        {
            wxSizerItem * const item = *i;

            if ( !item->IsShown() )
                continue;

            if ( majorSizes[n] == wxDefaultCoord )
            {
                const int propItem = item->GetProportion();
                majorSizes[n] = (remaining*propItem)/totalProportion;

                remaining -= majorSizes[n];
                totalProportion -= propItem;
            }
        }
    }


    // the position at which we put the next child
    wxPoint pt(m_position);


    // Final pass: finally do position the items correctly using their sizes as
    // determined above.
    for ( i = m_children.begin(), n = 0; i != m_children.end(); ++i, ++n )
    {
        wxSizerItem * const item = *i;

        if ( !item->IsShown() )
            continue;

        const int majorSize = majorSizes[n];

        const wxSize sizeThis(item->GetMinSizeWithBorder());

        // apply the alignment in the minor direction
        wxPoint posChild(pt);

        wxCoord minorSize = GetSizeInMinorDir(sizeThis);
        const int flag = item->GetFlag();
        if ( (flag & (wxEXPAND | wxSHAPED)) || (minorSize > totalMinorSize) )
        {
            // occupy all the available space if wxEXPAND was given and also if
            // the item is too big to fit -- in this case we truncate it below
            // its minimal size which is bad but better than not showing parts
            // of the window at all
            minorSize = totalMinorSize;
        }
        else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
        {
            PosInMinorDir(posChild) += totalMinorSize - minorSize;
        }
        // NB: wxCENTRE is used here only for backwards compatibility,
        //     wxALIGN_CENTRE should be used in new code
        else if ( flag & (wxCENTER | (IsVertical() ? wxALIGN_CENTRE_HORIZONTAL
                                                   : wxALIGN_CENTRE_VERTICAL)) )
        {
            PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
        }


        // apply RTL adjustment for horizontal sizers:
        if ( !IsVertical() && m_containingWindow )
        {
            posChild.x = m_containingWindow->AdjustForLayoutDirection
                                             (
                                                posChild.x,
                                                majorSize,
                                                m_size.x
                                             );
        }

        // finally set size of this child and advance to the next one
        item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));

        PosInMajorDir(pt) += majorSize;
    }
}

wxSize wxBoxSizer::CalcMin()
{
    m_totalProportion = 0;
    m_minSize = wxSize(0, 0);

    // The minimal size for the sizer should be big enough to allocate its
    // element at least its minimal size but also, and this is the non trivial
    // part, to respect the children proportion. To satisfy the latter
    // condition we must find the greatest min-size-to-proportion ratio for all
    // elements with non-zero proportion.
    float maxMinSizeToProp = 0.;
    for ( wxSizerItemList::const_iterator i = m_children.begin();
          i != m_children.end();
          ++i )
    {
        wxSizerItem * const item = *i;

        if ( !item->IsShown() )
            continue;

        const wxSize sizeMinThis = item->CalcMin();
        if ( const int propThis = item->GetProportion() )
        {
            float minSizeToProp = GetSizeInMajorDir(sizeMinThis);
            minSizeToProp /= propThis;

            if ( minSizeToProp > maxMinSizeToProp )
                maxMinSizeToProp = minSizeToProp;

            m_totalProportion += item->GetProportion();
        }
        else // fixed size item
        {
            // Just account for its size directly
            SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis);
        }

        // In the transversal direction we just need to find the maximum.
        if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) )
            SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis);
    }

    // Using the max ratio ensures that the min size is big enough for all
    // items to have their min size and satisfy the proportions among them.
    SizeInMajorDir(m_minSize) += (int)(maxMinSizeToProp*m_totalProportion);

    return m_minSize;
}

//---------------------------------------------------------------------------
// wxStaticBoxSizer
//---------------------------------------------------------------------------

#if wxUSE_STATBOX

wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
    : wxBoxSizer( orient ),
      m_staticBox( box )
{
    wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );

    // do this so that our Detach() is called if the static box is destroyed
    // before we are
    m_staticBox->SetContainingSizer(this);
}

wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
                : wxBoxSizer(orient),
                  m_staticBox(new wxStaticBox(win, wxID_ANY, s))
{
    // same as above
    m_staticBox->SetContainingSizer(this);
}

wxStaticBoxSizer::~wxStaticBoxSizer()
{
    delete m_staticBox;
}

void wxStaticBoxSizer::RecalcSizes()
{
    int top_border, other_border;
    m_staticBox->GetBordersForSizer(&top_border, &other_border);

    m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );

    wxSize old_size( m_size );
    m_size.x -= 2*other_border;
    m_size.y -= top_border + other_border;

    wxPoint old_pos( m_position );
    if (m_staticBox->GetChildren().GetCount() > 0)
    {
#if defined( __WXGTK20__ )
        // if the wxStaticBox has created a wxPizza to contain its children
        // (see wxStaticBox::AddChild) then we need to place the items it contains
        // in the wxBoxSizer::RecalcSizes() call below using coordinates relative
        // to the top-left corner of the staticbox:
        m_position.x = m_position.y = 0;
#elif defined(__WXOSX__) && wxOSX_USE_COCOA
        // the distance from the 'inner' content view to the embedded controls
        m_position.x = m_position.y = 10;
#else
        // if the wxStaticBox has childrens, then these windows must be placed
        // by the wxBoxSizer::RecalcSizes() call below using coordinates relative
        // to the top-left corner of the staticbox (but unlike wxGTK, we need
        // to keep in count the static borders here!):
        m_position.x = other_border;
        m_position.y = top_border;
#endif
    }
    else
    {
        // the windows contained in the staticbox have been created as siblings of the
        // staticbox (this is the "old" way of staticbox contents creation); in this
        // case we need to position them with coordinates relative to our common parent
        m_position.x += other_border;
        m_position.y += top_border;
    }

    wxBoxSizer::RecalcSizes();

    m_position = old_pos;
    m_size = old_size;
}

wxSize wxStaticBoxSizer::CalcMin()
{
    int top_border, other_border;
    m_staticBox->GetBordersForSizer(&top_border, &other_border);

    wxSize ret( wxBoxSizer::CalcMin() );
    ret.x += 2*other_border;

    // ensure that we're wide enough to show the static box label (there is no
    // need to check for the static box best size in vertical direction though)
    const int boxWidth = m_staticBox->GetBestSize().x;
    if ( ret.x < boxWidth )
        ret.x = boxWidth;

    ret.y += other_border + top_border;

    return ret;
}

void wxStaticBoxSizer::ShowItems( bool show )
{
    m_staticBox->Show( show );
    wxBoxSizer::ShowItems( show );
}

bool wxStaticBoxSizer::Detach( wxWindow *window )
{
    // avoid deleting m_staticBox in our dtor if it's being detached from the
    // sizer (which can happen because it's being already destroyed for
    // example)
    if ( window == m_staticBox )
    {
        m_staticBox = NULL;
        return true;
    }

    return wxSizer::Detach( window );
}

#endif // wxUSE_STATBOX

//---------------------------------------------------------------------------
// wxStdDialogButtonSizer
//---------------------------------------------------------------------------

#if wxUSE_BUTTON

wxStdDialogButtonSizer::wxStdDialogButtonSizer()
    : wxBoxSizer(wxHORIZONTAL)
{
    // Vertical buttons with lots of space on either side
    // looks rubbish on WinCE, so let's not do this for now.
    // If we are going to use vertical buttons, we should
    // put the sizer to the right of other controls in the dialog,
    // and that's beyond the scope of this sizer.
#ifndef __WXWINCE__
    bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
    // If we have a PDA screen, put yes/no button over
    // all other buttons, otherwise on the left side.
    if (is_pda)
        m_orient = wxVERTICAL;
#endif

    m_buttonAffirmative = NULL;
    m_buttonApply = NULL;
    m_buttonNegative = NULL;
    m_buttonCancel = NULL;
    m_buttonHelp = NULL;
}

void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
{
    switch (mybutton->GetId())
    {
        case wxID_OK:
        case wxID_YES:
        case wxID_SAVE:
            m_buttonAffirmative = mybutton;
            break;
        case wxID_APPLY:
            m_buttonApply = mybutton;
            break;
        case wxID_NO:
            m_buttonNegative = mybutton;
            break;
        case wxID_CANCEL:
        case wxID_CLOSE:
            m_buttonCancel = mybutton;
            break;
        case wxID_HELP:
        case wxID_CONTEXT_HELP:
            m_buttonHelp = mybutton;
            break;
        default:
            break;
    }
}

void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
{
    m_buttonAffirmative = button;
}

void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
{
    m_buttonNegative = button;
}

void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
{
    m_buttonCancel = button;
}

void wxStdDialogButtonSizer::Realize()
{
#ifdef __WXMAC__
        Add(0, 0, 0, wxLEFT, 6);
        if (m_buttonHelp)
            Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);

        if (m_buttonNegative){
            // HIG POLICE BULLETIN - destructive buttons need extra padding
            // 24 pixels on either side
            Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
        }

        // extra whitespace between help/negative and cancel/ok buttons
        Add(0, 0, 1, wxEXPAND, 0);

        if (m_buttonCancel){
            Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
            // Cancel or help should be default
            // m_buttonCancel->SetDefaultButton();
        }

        // Ugh, Mac doesn't really have apply dialogs, so I'll just
        // figure the best place is between Cancel and OK
        if (m_buttonApply)
            Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);

        if (m_buttonAffirmative){
            Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);

            if (m_buttonAffirmative->GetId() == wxID_SAVE){
                // these buttons have set labels under Mac so we should use them
                m_buttonAffirmative->SetLabel(_("Save"));
                if (m_buttonNegative)
                    m_buttonNegative->SetLabel(_("Don't Save"));
            }
        }

        // Extra space around and at the right
        Add(12, 40);
#elif defined(__WXGTK20__)
        // http://library.gnome.org/devel/hig-book/stable/windows-alert.html.en
        // says that the correct button order is
        //
        //      [Help]                  [Alternative] [Cancel] [Affirmative]

        // Flags ensuring that margins between the buttons are 6 pixels.
        const wxSizerFlags
            flagsBtn = wxSizerFlags().Centre().Border(wxLEFT | wxRIGHT, 3);

        // Margin around the entire sizer button should be 12.
        AddSpacer(9);

        if (m_buttonHelp)
            Add(m_buttonHelp, flagsBtn);

        // Align the rest of the buttons to the right.
        AddStretchSpacer();

        if (m_buttonNegative)
            Add(m_buttonNegative, flagsBtn);

        if (m_buttonApply)
            Add(m_buttonApply, flagsBtn);

        if (m_buttonCancel)
            Add(m_buttonCancel, flagsBtn);

        if (m_buttonAffirmative)
            Add(m_buttonAffirmative, flagsBtn);

        // Ensure that the right margin is 12 as well.
        AddSpacer(9);
#elif defined(__WXMSW__)
        // Windows

        // right-justify buttons
        Add(0, 0, 1, wxEXPAND, 0);

        if (m_buttonAffirmative){
            Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
        }

        if (m_buttonNegative){
            Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
        }

        if (m_buttonCancel){
            Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
        }
        if (m_buttonApply)
            Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);

        if (m_buttonHelp)
            Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
#else
        // GTK+1 and any other platform

        // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
        if (m_buttonHelp)
            Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);

        // extra whitespace between help and cancel/ok buttons
        Add(0, 0, 1, wxEXPAND, 0);

        if (m_buttonApply)
            Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);

        if (m_buttonAffirmative){
            Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
        }

        if (m_buttonNegative){
            Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
        }

        if (m_buttonCancel){
            Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
            // Cancel or help should be default
            // m_buttonCancel->SetDefaultButton();
        }

#endif
}

#endif // wxUSE_BUTTON
