/////////////////////////////////////////////////////////////////////////////
-// Name: sizer.cpp
+// Name: src/common/sizer.cpp
// Purpose: provide new wxSizer class for layout
// Author: Robert Roebling and Robin Dunn, contributions by
// Dirk Holtwick, Ron Lee
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
-#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
-#pragma implementation "sizer.h"
-#endif
-
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
+ #include "wx/math.h"
+ #include "wx/utils.h"
+ #include "wx/settings.h"
#endif // WX_PRECOMP
#include "wx/sizer.h"
-#include "wx/utils.h"
#include "wx/statbox.h"
-#include "wx/settings.h"
#include "wx/listimpl.cpp"
-#include "wx/intl.h"
+
#if WXWIN_COMPATIBILITY_2_4
#include "wx/notebook.h"
#endif
-#ifdef __WXMAC__
-# include "wx/mac/uma.h"
-#endif
-
//---------------------------------------------------------------------------
IMPLEMENT_CLASS(wxSizerItem, wxObject)
IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
#endif
-WX_DEFINE_EXPORTED_LIST( wxSizerItemList );
+WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
/*
TODO PROPERTIES
minsize
*/
-//---------------------------------------------------------------------------
+// ----------------------------------------------------------------------------
// wxSizerItem
-//---------------------------------------------------------------------------
-
-void wxSizerItem::Init()
-{
- m_window = NULL;
- m_sizer = NULL;
- m_show = true;
- m_userData = NULL;
- m_zoneRect = wxRect( 0, 0, 0, 0 );
-}
+// ----------------------------------------------------------------------------
void wxSizerItem::Init(const wxSizerFlags& flags)
{
m_border = flags.GetBorderInPixels();
}
-wxSizerItem::wxSizerItem( int width, int height, int proportion, int flag, int border, wxObject* userData )
- : m_window( NULL )
- , m_sizer( NULL )
- , m_size( wxSize( width, height ) ) // size is set directly
- , m_minSize( m_size ) // minimal size is the initial size
- , m_proportion( proportion )
- , m_border( border )
- , m_flag( flag )
- , m_zoneRect( 0, 0, 0, 0 )
- , m_show( true )
- , m_userData( userData )
-{
- SetRatio( m_size );
-}
-
-wxSizerItem::wxSizerItem( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
- : m_window( window )
- , m_sizer( NULL )
- , m_proportion( proportion )
- , m_border( border )
- , m_flag( flag )
- , m_zoneRect( 0, 0, 0, 0 )
- , m_show( true )
- , m_userData( userData )
-{
- if (flag & wxFIXED_MINSIZE)
- window->SetMinSize(window->GetSize());
+wxSizerItem::wxSizerItem()
+{
+ Init();
+
+ m_proportion = 0;
+ m_border = 0;
+ m_flag = 0;
+
+ m_kind = Item_None;
+}
+
+// window item
+void wxSizerItem::SetWindow(wxWindow *window)
+{
+ wxCHECK_RET( window, _T("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 );
+ SetRatio(m_minSize);
+}
- // m_size is calculated later
+wxSizerItem::wxSizerItem(wxWindow *window,
+ int proportion,
+ int flag,
+ int border,
+ wxObject* userData)
+ : m_proportion(proportion),
+ m_border(border),
+ m_flag(flag),
+ m_userData(userData)
+{
+ SetWindow(window);
}
-wxSizerItem::wxSizerItem( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
- : m_window( NULL )
- , m_sizer( sizer )
- , m_proportion( proportion )
- , m_border( border )
- , m_flag( flag )
- , m_zoneRect( 0, 0, 0, 0 )
- , m_show( true )
- , m_ratio( 0.0 )
- , m_userData( userData )
+// sizer item
+void wxSizerItem::SetSizer(wxSizer *sizer)
{
- // m_minSize is calculated later
- // m_size is calculated later
+ m_kind = Item_Sizer;
+ m_sizer = sizer;
}
-wxSizerItem::wxSizerItem()
+wxSizerItem::wxSizerItem(wxSizer *sizer,
+ int proportion,
+ int flag,
+ int border,
+ wxObject* userData)
+ : m_proportion(proportion),
+ m_border(border),
+ m_flag(flag),
+ m_ratio(0.0),
+ m_userData(userData)
{
- Init();
+ SetSizer(sizer);
- m_proportion = 0;
- m_border = 0;
- m_flag = 0;
+ // m_minSize is set later
+}
+
+// spacer item
+void wxSizerItem::SetSpacer(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_minSize(width, height), // minimal size is the initial size
+ m_proportion(proportion),
+ m_border(border),
+ m_flag(flag),
+ m_userData(userData)
+{
+ SetSpacer(width, height);
}
wxSizerItem::~wxSizerItem()
{
delete m_userData;
- if ( m_window )
+ switch ( m_kind )
{
- m_window->SetContainingSizer(NULL);
- }
- else // we must be a sizer
- {
- delete m_sizer;
+ 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( _T("unexpected wxSizerItem::m_kind") );
}
}
+wxSize wxSizerItem::GetSpacer() const
+{
+ wxSize size;
+ if ( m_kind == Item_Spacer )
+ size = m_spacer->GetSize();
+
+ return size;
+}
+
wxSize wxSizerItem::GetSize() const
{
wxSize ret;
- if (IsSizer())
- ret = m_sizer->GetSize();
- else
- if (IsWindow())
- ret = m_window->GetSize();
- else ret = m_size;
+ 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( _T("unexpected wxSizerItem::m_kind") );
+ }
if (m_flag & wxWEST)
ret.x += m_border;
// if we have to preserve aspect ratio _AND_ this is
// the first-time calculation, consider ret to be initial size
- if ((m_flag & wxSHAPED) && !m_ratio)
+ if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
SetRatio(m_minSize);
}
else if ( IsWindow() )
}
-void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
+void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
{
+ wxPoint pos = pos_;
+ wxSize size = size_;
if (m_flag & wxSHAPED)
{
// adjust aspect ratio
size.y -= m_border;
}
- if (IsSizer())
- m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
+ m_rect = wxRect(pos, size);
+
+ switch ( m_kind )
+ {
+ case Item_None:
+ wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
+ break;
+
+ case Item_Window:
+ m_window->SetSize(pos.x, pos.y, size.x, size.y,
+ wxSIZE_ALLOW_MINUS_ONE);
+ break;
+
+ case Item_Sizer:
+ m_sizer->SetDimension(pos.x, pos.y, size.x, size.y);
+ break;
- m_zoneRect = wxRect(pos, size);
- if (IsWindow())
- m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
+ case Item_Spacer:
+ m_spacer->SetSize(size);
+ break;
- m_size = size;
+ case Item_Max:
+ default:
+ wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
+ }
}
void wxSizerItem::DeleteWindows()
{
- if (m_window)
+ switch ( m_kind )
{
- m_window->Destroy();
- m_window = NULL;
+ 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( _T("unexpected wxSizerItem::m_kind") );
}
- if (m_sizer)
- m_sizer->DeleteWindows();
}
-bool wxSizerItem::IsWindow() const
+void wxSizerItem::Show( bool show )
{
- return (m_window != NULL);
-}
+ switch ( m_kind )
+ {
+ case Item_None:
+ wxFAIL_MSG( _T("can't show uninitialized sizer item") );
+ break;
-bool wxSizerItem::IsSizer() const
-{
- return (m_sizer != NULL);
-}
+ case Item_Window:
+ m_window->Show(show);
+ break;
-bool wxSizerItem::IsSpacer() const
-{
- return (m_window == NULL) && (m_sizer == NULL);
+ case Item_Sizer:
+ m_sizer->Show(show);
+ break;
+
+ case Item_Spacer:
+ m_spacer->Show(show);
+ break;
+
+ case Item_Max:
+ default:
+ wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
+ }
}
-void wxSizerItem::Show( bool show )
+bool wxSizerItem::IsShown() const
{
- m_show = show;
+ 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;
- if( IsWindow() )
- m_window->Show( show );
- else if( IsSizer() )
- m_sizer->ShowItems( show );
+ case Item_Spacer:
+ return m_spacer->IsShown();
- // ... nothing else to do to hide/show spacers
+ case Item_Max:
+ default:
+ wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
+ }
+
+ return false;
}
+#if WXWIN_COMPATIBILITY_2_6
void wxSizerItem::SetOption( int option )
{
SetProportion( option );
{
return GetProportion();
}
+#endif // WXWIN_COMPATIBILITY_2_6
//---------------------------------------------------------------------------
// wxSizer
//---------------------------------------------------------------------------
-wxSizer::wxSizer()
- : m_minSize( wxSize( 0, 0 ) )
-{
-}
-
wxSizer::~wxSizer()
{
WX_CLEAR_LIST(wxSizerItemList, m_children);
{
m_children.Insert( index, item );
- if( item->GetWindow() )
+ if ( item->GetWindow() )
item->GetWindow()->SetContainingSizer( this );
return item;
}
+#if WXWIN_COMPATIBILITY_2_6
bool wxSizer::Remove( wxWindow *window )
{
return Detach( window );
}
+#endif // WXWIN_COMPATIBILITY_2_6
bool wxSizer::Remove( wxSizer *sizer )
{
wxSizerItem *item = node->GetData();
- if( item->IsWindow() )
+ if ( item->IsWindow() )
item->GetWindow()->SetContainingSizer( NULL );
delete item;
wxSizerItem *item = node->GetData();
- if( item->IsSizer() )
+ if ( item->IsSizer() )
item->DetachSizer();
- else if( item->IsWindow() )
+ else if ( item->IsWindow() )
item->GetWindow()->SetContainingSizer( NULL );
delete item;
// Return a window size that will fit within the screens dimensions
wxSize wxSizer::FitSize( wxWindow *window )
{
+ if ( window->IsTopLevel() )
+ {
+ wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
+ if ( tlw && tlw->IsAlwaysMaximized() )
+ {
+ return tlw->GetClientSize();
+ }
+ }
+
wxSize size = GetMinWindowSize( window );
wxSize sizeMax = GetMaxWindowSize( window );
{
wxSize maxSize( window->GetMaxSize() );
- if( maxSize != wxDefaultSize )
+ if ( maxSize != wxDefaultSize )
{
wxSize size( window->GetSize() );
wxSize client_size( window->GetClientSize() );
//---------------------------------------------------------------------------
wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
- : m_rows( rows )
+ : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
, m_cols( cols )
, m_vgap( vgap )
, m_hgap( hgap )
{
- if (m_rows == 0 && m_cols == 0)
- m_rows = 1;
}
wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
- : m_rows( 0 )
+ : m_rows( cols == 0 ? 1 : 0 )
, m_cols( cols )
, m_vgap( vgap )
, m_hgap( hgap )
{
- if (m_rows == 0 && m_cols == 0)
- m_rows = 1;
}
int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
SetItemBounds( node->GetData(), x, y, w, h);
}
- y = y + m_rowHeights[r] + m_vgap;
+ if (m_rowHeights[r] != -1)
+ y = y + m_rowHeights[r] + m_vgap;
}
- x = x + m_colWidths[c] + m_hgap;
+ if (m_colWidths[c] != -1)
+ x = x + m_colWidths[c] + m_hgap;
}
}
int width = 0;
for (int col = 0; col < ncols; col++)
if ( m_colWidths[ col ] != -1 )
- width += m_colWidths[ col ] + ( col == ncols-1 ? 0 : m_hgap );
+ width += m_colWidths[ col ] + m_hgap;
+ if (width > 0)
+ width -= m_hgap;
int height = 0;
for (int row = 0; row < nrows; row++)
if ( m_rowHeights[ row ] != -1 )
- height += m_rowHeights[ row ] + ( row == nrows-1 ? 0 : m_vgap );
+ height += m_rowHeights[ row ] + m_vgap;
+ if (height > 0)
+ height -= m_vgap;
m_calculatedMinSize = wxSize( width, height );
return m_calculatedMinSize;
wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
: m_rowHeights;
- const int count = array.GetCount();
+ const size_t count = array.GetCount();
// find the largest value in this array
- int n, largest = 0;
+ size_t n;
+ int largest = 0;
+
for ( n = 0; n < count; ++n )
{
if ( array[n] > largest )
{
wxSizerItem *item = node->GetData();
- if (item->IsShown())
+ if ( item->IsShown() )
+ {
item->CalcMin(); // result is stored in the item
- if (item->IsShown() && item->GetProportion() != 0)
m_stretchable += item->GetProportion();
+ }
node = node->GetNext();
}
#if wxUSE_STATBOX
wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
- : wxBoxSizer( orient )
- , m_staticBox( box )
+ : 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;
}
static void GetStaticBoxBorders( wxStaticBox *box,
{
// this has to be done platform by platform as there is no way to
// guess the thickness of a wxStaticBox border
-#ifdef __WXCOCOA__
- box->GetBordersForSizer(borderTop,borderOther);
-#elif defined(__WXMAC__)
-
- static int extraTop = -1; // Uninitted
- static int other = 5;
-
- if ( extraTop == -1 )
- {
- // The minimal border used for the top. Later on the staticbox'
- // font height is added to this.
- extraTop = 0;
-
- if ( UMAGetSystemVersion() >= 0x1030 /*Panther*/ )
- {
- // As indicated by the HIG, Panther needs an extra border of 11
- // pixels (otherwise overlapping occurs at the top). The "other"
- // border has to be 11.
- extraTop = 11;
- other = 11;
- }
-
- }
-
- *borderTop = extraTop + box->GetCharHeight();
- *borderOther = other;
-
-#else
-#ifdef __WXGTK__
- if ( box->GetLabel().empty() )
- *borderTop = 5;
- else
-#endif // __WXGTK__
- *borderTop = box->GetCharHeight();
-
- *borderOther = 5;
-#endif // __WXCOCOA__
+ box->GetBordersForSizer(borderTop, borderOther);
}
void wxStaticBoxSizer::RecalcSizes()
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
#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_buttonCancel = mybutton;
break;
case wxID_HELP:
+ case wxID_CONTEXT_HELP:
m_buttonHelp = mybutton;
break;
default:
m_buttonCancel = button;
}
-void wxStdDialogButtonSizer::Finalise()
+void wxStdDialogButtonSizer::Realize()
{
#ifdef __WXMAC__
Add(0, 0, 0, wxLEFT, 6);
if (m_buttonAffirmative)
Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
+#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
- // do the same thing for GTK1 and Windows platforms
- // and assume any platform not accounted for here will use
- // Windows style
- Add(0, 0, 0, wxLEFT, 9);
+ // 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);
}
if (m_buttonCancel){
- Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
+ 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();
}
#if wxUSE_BOOKCTRL
+#if WXWIN_COMPATIBILITY_2_6
+
wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
: m_bookctrl(bookctrl)
{
wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
}
+#endif // WXWIN_COMPATIBILITY_2_6
+
void wxBookCtrlSizer::RecalcSizes()
{
m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
wxSize wxBookCtrlSizer::CalcMin()
{
- wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
+ wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
sizeBorder.x += 5;
sizeBorder.y += 5;
#if wxUSE_NOTEBOOK
+#if WXWIN_COMPATIBILITY_2_6
+
wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
{
wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
m_bookctrl = nb;
}
+#endif // WXWIN_COMPATIBILITY_2_6
+
#endif // wxUSE_NOTEBOOOK
#endif // wxUSE_BOOKCTRL