/////////////////////////////////////////////////////////////////////////////
-// 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
#pragma hdrstop
#endif
+#include "wx/display.h"
+#include "wx/sizer.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/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
IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
#endif
-WX_DEFINE_EXPORTED_LIST( wxSizerItemList );
+WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
/*
TODO PROPERTIES
// 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() )
{
// Since the size of the window may change during runtime, we
// should use the current minimal/best size.
- m_minSize = m_window->GetBestFittingSize();
+ m_minSize = m_window->GetEffectiveMinSize();
}
return GetMinSizeWithBorder();
}
-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 (size.x < 0)
+ size.x = 0;
+ if (size.y < 0)
+ size.y = 0;
+
m_rect = wxRect(pos, size);
switch ( m_kind )
return m_window->IsShown();
case Item_Sizer:
- return m_sizer->IsShown();
+ // 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();
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_isShown = true;
-}
-
wxSizer::~wxSizer()
{
WX_CLEAR_LIST(wxSizerItemList, m_children);
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 )
{
return true;
}
+bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
+{
+ wxASSERT_MSG( oldwin, _T("Replacing NULL window") );
+ wxASSERT_MSG( newwin, _T("Replacing with NULL window") );
+
+ wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxSizerItem *item = node->GetData();
+
+ if (item->GetWindow() == oldwin)
+ {
+ item->GetWindow()->SetContainingSizer( NULL );
+ item->SetWindow(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, _T("Replacing NULL sizer") );
+ wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") );
+
+ wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxSizerItem *item = node->GetData();
+
+ if (item->GetSizer() == oldsz)
+ {
+ wxSizer *old = item->GetSizer();
+ item->SetSizer(newsz);
+ delete old;
+ 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, _T("Replace index is out of range") );
+ wxASSERT_MSG( newitem, _T("Replacing with NULL item") );
+
+ wxSizerItemList::compatibility_iterator node = m_children.Item( old );
+
+ wxCHECK_MSG( node, false, _T("Failed to find child node") );
+
+ wxSizerItem *item = node->GetData();
+ node->SetData(newitem);
+ delete item;
+
+ return true;
+}
+
void wxSizer::Clear( bool delete_windows )
{
// First clear the ContainingSizer pointers
wxSize wxSizer::Fit( wxWindow *window )
{
- wxSize size(window->IsTopLevel() ? FitSize(window)
- : GetMinWindowSize(window));
+ // take the min size by default and limit it by max size
+ wxSize size = GetMinWindowSize(window);
+ wxSize sizeMax = GetMaxWindowSize(window);
+
+ wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
+ if ( tlw )
+ {
+ // hack for small screen devices where TLWs are always full screen
+ if ( tlw->IsAlwaysMaximized() )
+ {
+ size = tlw->GetSize();
+ }
+ else // normal situation
+ {
+ // 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 ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
+ size.x = sizeMax.x;
+ if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
+ size.y = sizeMax.y;
+
window->SetSize( size );
// 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
-
-// Return a window size that will fit within the screens dimensions
-wxSize wxSizer::FitSize( wxWindow *window )
-{
- wxSize size = GetMinWindowSize( window );
- wxSize sizeMax = GetMaxWindowSize( 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::GetMaxClientSize( wxWindow *window ) const
{
wxSize maxSize( window->GetMaxSize() );
{
int nrows, ncols;
if ( CalcRowsCols(nrows, ncols) == 0 )
- return wxSize(10, 10);
+ return wxSize();
// Find the max width and height for any component
int w = 0;
// Number of rows/columns can change as items are added or removed.
if ( !CalcRowsCols(nrows, ncols) )
- return wxSize(10, 10);
+ return wxSize();
m_rowHeights.SetCount(nrows);
m_colWidths.SetCount(ncols);
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 )
m_growableRowsProportions.Add( proportion );
}
-void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
-{
- m_growableRows.Remove( idx );
-}
-
void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
{
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( _T("column/row is already not growable") );
+}
+
void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
{
- m_growableCols.Remove( idx );
+ DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
+}
+
+void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
+{
+ DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
}
//---------------------------------------------------------------------------
// wxALIGN_CENTER should be used in new code
child_pos.y += (m_size.y - size.y) / 2;
+ if ( m_containingWindow )
+ {
+ child_pos.x = m_containingWindow->AdjustForLayoutDirection
+ (
+ child_pos.x,
+ width,
+ m_size.x
+ );
+ }
+
item->SetDimension( child_pos, child_size );
pt.x += width;
wxSize wxBoxSizer::CalcMin()
{
if (m_children.GetCount() == 0)
- return wxSize(10,10);
+ return wxSize();
m_stretchable = 0;
m_minWidth = 0;
#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,
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
#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 );
#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