1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn
5 // Modified by: Ron Lee
8 // Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
10 // Licence: wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
14 #pragma implementation "sizer.h"
17 // For compilers that support precompilation, includes "wx.h".
18 #include "wx/wxprec.h"
26 #include "wx/statbox.h"
27 #include "wx/notebook.h"
28 #include <wx/listimpl.cpp>
30 //---------------------------------------------------------------------------
32 IMPLEMENT_CLASS(wxSizerItem
, wxObject
)
33 IMPLEMENT_CLASS(wxSizer
, wxObject
)
34 IMPLEMENT_CLASS(wxGridSizer
, wxSizer
)
35 IMPLEMENT_CLASS(wxFlexGridSizer
, wxGridSizer
)
36 IMPLEMENT_CLASS(wxBoxSizer
, wxSizer
)
38 IMPLEMENT_CLASS(wxStaticBoxSizer
, wxBoxSizer
)
41 IMPLEMENT_CLASS(wxNotebookSizer
, wxSizer
)
44 WX_DEFINE_EXPORTED_LIST( wxSizerItemList
);
47 //---------------------------------------------------------------------------
49 //---------------------------------------------------------------------------
51 wxSizerItem::wxSizerItem( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData
)
54 , m_size( wxSize( width
, height
) ) // size is set directly
55 , m_minSize( m_size
) // minimal size is the initial size
56 , m_proportion( proportion
)
60 , m_userData( userData
)
65 wxSizerItem::wxSizerItem( wxWindow
*window
, int proportion
, int flag
, int border
, wxObject
* userData
)
68 , m_minSize( window
->GetSize() ) // minimal size is the initial size
69 , m_proportion( proportion
)
73 , m_userData( userData
)
75 // aspect ratio calculated from initial size
76 SetRatio( m_minSize
);
78 // m_size is calculated later
81 wxSizerItem::wxSizerItem( wxSizer
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData
)
84 , m_proportion( proportion
)
89 , m_userData( userData
)
91 // m_minSize is calculated later
92 // m_size is calculated later
95 wxSizerItem::~wxSizerItem()
104 wxSize
wxSizerItem::GetSize() const
108 ret
= m_sizer
->GetSize();
111 ret
= m_window
->GetSize();
118 if (m_flag
& wxNORTH
)
120 if (m_flag
& wxSOUTH
)
126 wxSize
wxSizerItem::CalcMin()
131 ret
= m_sizer
->GetMinSize();
133 // if we have to preserve aspect ratio _AND_ this is
134 // the first-time calculation, consider ret to be initial size
135 if ((m_flag
& wxSHAPED
) && !m_ratio
)
140 if ( IsWindow() && (m_flag
& wxADJUST_MINSIZE
) )
142 // By user request, keep the minimal size for this item
143 // in sync with the largest of BestSize and any user supplied
144 // minimum size hint. Useful in cases where the item is
145 // changeable -- static text labels, etc.
146 m_minSize
= m_window
->GetAdjustedBestSize();
156 if (m_flag
& wxNORTH
)
158 if (m_flag
& wxSOUTH
)
164 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size
)
166 if (m_flag
& wxSHAPED
)
168 // adjust aspect ratio
169 int rwidth
= (int) (size
.y
* m_ratio
);
173 int rheight
= (int) (size
.x
/ m_ratio
);
174 // add vertical space
175 if (m_flag
& wxALIGN_CENTER_VERTICAL
)
176 pos
.y
+= (size
.y
- rheight
) / 2;
177 else if (m_flag
& wxALIGN_BOTTOM
)
178 pos
.y
+= (size
.y
- rheight
);
179 // use reduced dimensions
182 else if (rwidth
< size
.x
)
184 // add horizontal space
185 if (m_flag
& wxALIGN_CENTER_HORIZONTAL
)
186 pos
.x
+= (size
.x
- rwidth
) / 2;
187 else if (m_flag
& wxALIGN_RIGHT
)
188 pos
.x
+= (size
.x
- rwidth
);
193 // This is what GetPosition() returns. Since we calculate
194 // borders afterwards, GetPosition() will be the left/top
195 // corner of the surrounding border.
207 if (m_flag
& wxNORTH
)
212 if (m_flag
& wxSOUTH
)
218 m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y
);
221 m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
, wxSIZE_ALLOW_MINUS_ONE
);
226 void wxSizerItem::DeleteWindows()
232 m_sizer
->DeleteWindows();
235 bool wxSizerItem::IsWindow() const
237 return (m_window
!= NULL
);
240 bool wxSizerItem::IsSizer() const
242 return (m_sizer
!= NULL
);
245 bool wxSizerItem::IsSpacer() const
247 return (m_window
== NULL
) && (m_sizer
== NULL
);
250 void wxSizerItem::Show( bool show
)
255 m_window
->Show( show
);
257 m_sizer
->ShowItems( show
);
259 // ... nothing else to do to hide/show spacers
262 void wxSizerItem::SetOption( int option
)
264 SetProportion( option
);
267 int wxSizerItem::GetOption() const
269 return GetProportion();
273 //---------------------------------------------------------------------------
275 //---------------------------------------------------------------------------
278 : m_minSize( wxSize( 0, 0 ) )
280 m_children
.DeleteContents( true );
288 void wxSizer::Add( wxWindow
*window
, int proportion
, int flag
, int border
, wxObject
* userData
)
290 m_children
.Append( new wxSizerItem( window
, proportion
, flag
, border
, userData
) );
291 window
->SetContainingSizer( this );
294 void wxSizer::Add( wxSizer
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData
)
296 m_children
.Append( new wxSizerItem( sizer
, proportion
, flag
, border
, userData
) );
299 void wxSizer::Add( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData
)
301 m_children
.Append( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData
) );
304 void wxSizer::Add( wxSizerItem
*item
)
306 m_children
.Append( item
);
308 if( item
->GetWindow() )
309 item
->GetWindow()->SetContainingSizer( this );
312 void wxSizer::Prepend( wxWindow
*window
, int proportion
, int flag
, int border
, wxObject
* userData
)
314 m_children
.Insert( new wxSizerItem( window
, proportion
, flag
, border
, userData
) );
315 window
->SetContainingSizer( this );
318 void wxSizer::Prepend( wxSizer
*sizer
, int proportion
, int flag
, int border
, wxObject
* userData
)
320 m_children
.Insert( new wxSizerItem( sizer
, proportion
, flag
, border
, userData
) );
323 void wxSizer::Prepend( int width
, int height
, int proportion
, int flag
, int border
, wxObject
* userData
)
325 m_children
.Insert( new wxSizerItem( width
, height
, proportion
, flag
, border
, userData
) );
328 void wxSizer::Prepend( wxSizerItem
*item
)
330 m_children
.Insert( item
);
332 if( item
->GetWindow() )
333 item
->GetWindow()->SetContainingSizer( this );
336 void wxSizer::Insert( size_t index
,
343 m_children
.Insert( index
,
344 new wxSizerItem( window
, proportion
, flag
, border
, userData
) );
345 window
->SetContainingSizer( this );
348 void wxSizer::Insert( size_t index
,
355 m_children
.Insert( index
,
356 new wxSizerItem( sizer
, proportion
, flag
, border
, userData
) );
359 void wxSizer::Insert( size_t index
,
367 m_children
.Insert( index
,
368 new wxSizerItem( width
, height
, proportion
, flag
, border
, userData
) );
371 void wxSizer::Insert( size_t index
, wxSizerItem
*item
)
373 m_children
.Insert( index
, item
);
375 if( item
->GetWindow() )
376 item
->GetWindow()->SetContainingSizer( this );
379 bool wxSizer::Remove( wxWindow
*window
)
381 return Detach( window
);
384 bool wxSizer::Remove( wxSizer
*sizer
)
386 wxASSERT_MSG( sizer
, _T("Removing NULL sizer") );
388 wxSizerItemList::Node
*node
= m_children
.GetFirst();
391 wxSizerItem
*item
= node
->GetData();
393 if (item
->GetSizer() == sizer
)
394 return m_children
.DeleteNode( node
);
396 node
= node
->GetNext();
402 bool wxSizer::Remove( int index
)
404 wxCHECK_MSG( index
>= 0 && (size_t)index
< m_children
.GetCount(),
406 _T("Remove index is out of range") );
408 wxSizerItemList::Node
*node
= m_children
.Item( index
);
410 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
412 wxSizerItem
*item
= node
->GetData();
414 if( item
->IsWindow() )
415 item
->GetWindow()->SetContainingSizer( NULL
);
417 return m_children
.DeleteNode( node
);
420 bool wxSizer::Detach( wxSizer
*sizer
)
422 wxASSERT_MSG( sizer
, _T("Detaching NULL sizer") );
424 wxSizerItemList::Node
*node
= m_children
.GetFirst();
427 wxSizerItem
*item
= node
->GetData();
429 if (item
->GetSizer() == sizer
)
432 return m_children
.DeleteNode( node
);
434 node
= node
->GetNext();
440 bool wxSizer::Detach( wxWindow
*window
)
442 wxASSERT_MSG( window
, _T("Detaching NULL window") );
444 wxSizerItemList::Node
*node
= m_children
.GetFirst();
447 wxSizerItem
*item
= node
->GetData();
449 if (item
->GetWindow() == window
)
451 item
->GetWindow()->SetContainingSizer( NULL
);
452 return m_children
.DeleteNode( node
);
454 node
= node
->GetNext();
460 bool wxSizer::Detach( int index
)
462 wxCHECK_MSG( index
>= 0 && (size_t)index
< m_children
.GetCount(),
464 _T("Detach index is out of range") );
466 wxSizerItemList::Node
*node
= m_children
.Item( index
);
468 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
470 wxSizerItem
*item
= node
->GetData();
472 if( item
->IsSizer() )
474 else if( item
->IsWindow() )
475 item
->GetWindow()->SetContainingSizer( NULL
);
477 return m_children
.DeleteNode( node
);
480 void wxSizer::Clear( bool delete_windows
)
482 // First clear the ContainingSizer pointers
483 wxSizerItemList::Node
*node
= m_children
.GetFirst();
486 wxSizerItem
*item
= node
->GetData();
488 if (item
->IsWindow())
489 item
->GetWindow()->SetContainingSizer( NULL
);
490 node
= node
->GetNext();
493 // Destroy the windows if needed
497 // Now empty the list
501 void wxSizer::DeleteWindows()
503 wxSizerItemList::Node
*node
= m_children
.GetFirst();
506 wxSizerItem
*item
= node
->GetData();
508 item
->DeleteWindows();
509 node
= node
->GetNext();
513 wxSize
wxSizer::Fit( wxWindow
*window
)
516 if (window
->IsTopLevel())
517 size
= FitSize( window
);
519 size
= GetMinWindowSize( window
);
521 window
->SetSize( size
);
526 void wxSizer::FitInside( wxWindow
*window
)
529 if (window
->IsTopLevel())
530 size
= VirtualFitSize( window
);
532 size
= GetMinClientSize( window
);
534 window
->SetVirtualSize( size
);
537 void wxSizer::Layout()
543 void wxSizer::SetSizeHints( wxWindow
*window
)
545 // Preserve the window's max size hints, but set the
546 // lower bound according to the sizer calculations.
548 wxSize size
= Fit( window
);
550 window
->SetSizeHints( size
.x
,
552 window
->GetMaxWidth(),
553 window
->GetMaxHeight() );
556 void wxSizer::SetVirtualSizeHints( wxWindow
*window
)
558 // Preserve the window's max size hints, but set the
559 // lower bound according to the sizer calculations.
562 wxSize
size( window
->GetVirtualSize() );
563 window
->SetVirtualSizeHints( size
.x
,
565 window
->GetMaxWidth(),
566 window
->GetMaxHeight() );
569 wxSize
wxSizer::GetMaxWindowSize( wxWindow
*window
) const
571 return window
->GetMaxSize();
574 wxSize
wxSizer::GetMinWindowSize( wxWindow
*window
)
576 wxSize
minSize( GetMinSize() );
577 wxSize
size( window
->GetSize() );
578 wxSize
client_size( window
->GetClientSize() );
580 return wxSize( minSize
.x
+size
.x
-client_size
.x
,
581 minSize
.y
+size
.y
-client_size
.y
);
584 // Return a window size that will fit within the screens dimensions
585 wxSize
wxSizer::FitSize( wxWindow
*window
)
587 wxSize size
= GetMinWindowSize( window
);
588 wxSize sizeMax
= GetMaxWindowSize( window
);
590 // Limit the size if sizeMax != wxDefaultSize
592 if ( size
.x
> sizeMax
.x
&& sizeMax
.x
!= -1 )
594 if ( size
.y
> sizeMax
.y
&& sizeMax
.y
!= -1 )
600 wxSize
wxSizer::GetMaxClientSize( wxWindow
*window
) const
602 wxSize
maxSize( window
->GetMaxSize() );
604 if( maxSize
!= wxDefaultSize
)
606 wxSize
size( window
->GetSize() );
607 wxSize
client_size( window
->GetClientSize() );
609 return wxSize( maxSize
.x
+ client_size
.x
- size
.x
,
610 maxSize
.y
+ client_size
.y
- size
.y
);
613 return wxDefaultSize
;
616 wxSize
wxSizer::GetMinClientSize( wxWindow
*WXUNUSED(window
) )
618 return GetMinSize(); // Already returns client size.
621 wxSize
wxSizer::VirtualFitSize( wxWindow
*window
)
623 wxSize size
= GetMinClientSize( window
);
624 wxSize sizeMax
= GetMaxClientSize( window
);
626 // Limit the size if sizeMax != wxDefaultSize
628 if ( size
.x
> sizeMax
.x
&& sizeMax
.x
!= -1 )
630 if ( size
.y
> sizeMax
.y
&& sizeMax
.y
!= -1 )
636 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
645 wxSize
wxSizer::GetMinSize()
647 wxSize
ret( CalcMin() );
648 if (ret
.x
< m_minSize
.x
) ret
.x
= m_minSize
.x
;
649 if (ret
.y
< m_minSize
.y
) ret
.y
= m_minSize
.y
;
653 void wxSizer::DoSetMinSize( int width
, int height
)
656 m_minSize
.y
= height
;
659 bool wxSizer::DoSetItemMinSize( wxWindow
*window
, int width
, int height
)
661 wxASSERT_MSG( window
, _T("SetMinSize for NULL window") );
663 // Is it our immediate child?
665 wxSizerItemList::Node
*node
= m_children
.GetFirst();
668 wxSizerItem
*item
= node
->GetData();
670 if (item
->GetWindow() == window
)
672 item
->SetInitSize( width
, height
);
675 node
= node
->GetNext();
678 // No? Search any subsizers we own then
680 node
= m_children
.GetFirst();
683 wxSizerItem
*item
= node
->GetData();
685 if ( item
->GetSizer() &&
686 item
->GetSizer()->DoSetItemMinSize( window
, width
, height
) )
688 // A child sizer found the requested windw, exit.
691 node
= node
->GetNext();
697 bool wxSizer::DoSetItemMinSize( wxSizer
*sizer
, int width
, int height
)
699 wxASSERT_MSG( sizer
, _T("SetMinSize for NULL sizer") );
701 // Is it our immediate child?
703 wxSizerItemList::Node
*node
= m_children
.GetFirst();
706 wxSizerItem
*item
= node
->GetData();
708 if (item
->GetSizer() == sizer
)
710 item
->GetSizer()->DoSetMinSize( width
, height
);
713 node
= node
->GetNext();
716 // No? Search any subsizers we own then
718 node
= m_children
.GetFirst();
721 wxSizerItem
*item
= node
->GetData();
723 if ( item
->GetSizer() &&
724 item
->GetSizer()->DoSetItemMinSize( sizer
, width
, height
) )
726 // A child found the requested sizer, exit.
729 node
= node
->GetNext();
735 bool wxSizer::DoSetItemMinSize( size_t index
, int width
, int height
)
737 wxSizerItemList::Node
*node
= m_children
.Item( index
);
739 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
741 wxSizerItem
*item
= node
->GetData();
743 if (item
->GetSizer())
745 // Sizers contains the minimal size in them, if not calculated ...
746 item
->GetSizer()->DoSetMinSize( width
, height
);
750 // ... but the minimal size of spacers and windows in stored in them
751 item
->SetInitSize( width
, height
);
757 void wxSizer::Show( wxWindow
*window
, bool show
)
759 wxASSERT_MSG( window
, _T("Show for NULL window") );
761 wxSizerItemList::Node
*node
= m_children
.GetFirst();
764 wxSizerItem
*item
= node
->GetData();
766 if (item
->GetWindow() == window
)
771 node
= node
->GetNext();
775 void wxSizer::Show( wxSizer
*sizer
, bool show
)
777 wxASSERT_MSG( sizer
, _T("Show for NULL sizer") );
779 wxSizerItemList::Node
*node
= m_children
.GetFirst();
782 wxSizerItem
*item
= node
->GetData();
784 if (item
->GetSizer() == sizer
)
789 node
= node
->GetNext();
793 void wxSizer::Show( size_t index
, bool show
)
795 wxCHECK_RET( index
< m_children
.GetCount(),
796 _T("Show index is out of range") );
798 m_children
.Item( index
)->GetData()->Show( show
);
801 void wxSizer::ShowItems( bool show
)
803 wxSizerItemList::Node
*node
= m_children
.GetFirst();
806 node
->GetData()->Show( show
);
807 node
= node
->GetNext();
811 bool wxSizer::IsShown( wxWindow
*window
) const
813 wxSizerItemList::Node
*node
= m_children
.GetFirst();
816 wxSizerItem
*item
= node
->GetData();
818 if (item
->GetWindow() == window
)
820 return item
->IsShown();
822 node
= node
->GetNext();
825 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
830 bool wxSizer::IsShown( wxSizer
*sizer
) const
832 wxSizerItemList::Node
*node
= m_children
.GetFirst();
835 wxSizerItem
*item
= node
->GetData();
837 if (item
->GetSizer() == sizer
)
839 return item
->IsShown();
841 node
= node
->GetNext();
844 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
849 bool wxSizer::IsShown( size_t index
) const
851 wxCHECK_MSG( index
< m_children
.GetCount(),
853 _T("IsShown index is out of range") );
855 return m_children
.Item( index
)->GetData()->IsShown();
859 //---------------------------------------------------------------------------
861 //---------------------------------------------------------------------------
863 wxGridSizer::wxGridSizer( int rows
, int cols
, int vgap
, int hgap
)
871 wxGridSizer::wxGridSizer( int cols
, int vgap
, int hgap
)
879 int wxGridSizer::CalcRowsCols(int& nrows
, int& ncols
) const
881 int nitems
= m_children
.GetCount();
887 nrows
= (nitems
+ m_cols
- 1) / m_cols
;
891 ncols
= (nitems
+ m_rows
- 1) / m_rows
;
894 else // 0 columns, 0 rows?
896 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
905 void wxGridSizer::RecalcSizes()
907 int nitems
, nrows
, ncols
;
908 if ( (nitems
= CalcRowsCols(nrows
, ncols
)) == 0 )
911 wxSize
sz( GetSize() );
912 wxPoint
pt( GetPosition() );
914 int w
= (sz
.x
- (ncols
- 1) * m_hgap
) / ncols
;
915 int h
= (sz
.y
- (nrows
- 1) * m_vgap
) / nrows
;
918 for (int c
= 0; c
< ncols
; c
++)
921 for (int r
= 0; r
< nrows
; r
++)
923 int i
= r
* ncols
+ c
;
926 wxSizerItemList::Node
*node
= m_children
.Item( i
);
928 wxASSERT_MSG( node
, _T("Failed to find SizerItemList node") );
930 SetItemBounds( node
->GetData(), x
, y
, w
, h
);
938 wxSize
wxGridSizer::CalcMin()
940 int nitems
, nrows
, ncols
;
941 if ( (nitems
= CalcRowsCols(nrows
, ncols
)) == 0 )
942 return wxSize(10, 10);
944 // Find the max width and height for any component
948 wxSizerItemList::Node
*node
= m_children
.GetFirst();
951 wxSizerItem
*item
= node
->GetData();
952 wxSize
sz( item
->CalcMin() );
954 w
= wxMax( w
, sz
.x
);
955 h
= wxMax( h
, sz
.y
);
957 node
= node
->GetNext();
960 return wxSize( ncols
* w
+ (ncols
-1) * m_hgap
,
961 nrows
* h
+ (nrows
-1) * m_vgap
);
964 void wxGridSizer::SetItemBounds( wxSizerItem
*item
, int x
, int y
, int w
, int h
)
967 wxSize
sz( item
->CalcMin() );
968 int flag
= item
->GetFlag();
970 if ((flag
& wxEXPAND
) || (flag
& wxSHAPED
))
976 if (flag
& wxALIGN_CENTER_HORIZONTAL
)
978 pt
.x
= x
+ (w
- sz
.x
) / 2;
980 else if (flag
& wxALIGN_RIGHT
)
982 pt
.x
= x
+ (w
- sz
.x
);
985 if (flag
& wxALIGN_CENTER_VERTICAL
)
987 pt
.y
= y
+ (h
- sz
.y
) / 2;
989 else if (flag
& wxALIGN_BOTTOM
)
991 pt
.y
= y
+ (h
- sz
.y
);
995 item
->SetDimension(pt
, sz
);
998 //---------------------------------------------------------------------------
1000 //---------------------------------------------------------------------------
1002 wxFlexGridSizer::wxFlexGridSizer( int rows
, int cols
, int vgap
, int hgap
)
1003 : wxGridSizer( rows
, cols
, vgap
, hgap
),
1004 m_flexDirection(wxBOTH
),
1005 m_growMode(wxFLEX_GROWMODE_SPECIFIED
)
1009 wxFlexGridSizer::wxFlexGridSizer( int cols
, int vgap
, int hgap
)
1010 : wxGridSizer( cols
, vgap
, hgap
),
1011 m_flexDirection(wxBOTH
),
1012 m_growMode(wxFLEX_GROWMODE_SPECIFIED
)
1016 wxFlexGridSizer::~wxFlexGridSizer()
1020 void wxFlexGridSizer::RecalcSizes()
1022 int nitems
, nrows
, ncols
;
1023 if ( (nitems
= CalcRowsCols(nrows
, ncols
)) == 0 )
1026 wxSize
sz( GetSize() );
1027 wxSize
minsz( CalcMin() );
1028 wxPoint
pt( GetPosition() );
1033 // what to do with the rows? by default, resize them proportionally
1034 if ( (m_flexDirection
& wxVERTICAL
) ||
1035 (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) )
1037 // Transfer only those rows into temp which exist in the sizer
1038 // ignoring the superfluous ones. This prevents a segfault when
1039 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
1040 for (idx
= 0; idx
< m_growableRows
.GetCount(); idx
++)
1042 if (m_growableRows
[idx
] < nrows
)
1043 temp
.Add( m_growableRows
[idx
] );
1046 num
= temp
.GetCount();
1048 if ((num
> 0) && (sz
.y
> minsz
.y
))
1050 delta
= (sz
.y
- minsz
.y
) / num
;
1051 for (idx
= 0; idx
< num
; idx
++)
1052 m_rowHeights
[ temp
[idx
] ] += delta
;
1056 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.y
> minsz
.y
) )
1058 // rounding problem?
1059 for ( int row
= 0; row
< nrows
; ++row
)
1060 m_rowHeights
[ row
] = sz
.y
/ nrows
;
1063 // the same logic as above but for the columns
1064 if ( (m_flexDirection
& wxHORIZONTAL
) ||
1065 (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) )
1068 for (idx
= 0; idx
< m_growableCols
.GetCount(); idx
++)
1070 if (m_growableCols
[idx
] < ncols
)
1071 temp
.Add( m_growableCols
[idx
] );
1074 num
= temp
.GetCount();
1076 if ((num
> 0) && (sz
.x
> minsz
.x
))
1078 delta
= (sz
.x
- minsz
.x
) / num
;
1079 for (idx
= 0; idx
< num
; idx
++)
1080 m_colWidths
[ temp
[idx
] ] += delta
;
1083 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.x
> minsz
.x
) )
1085 for ( int col
=0; col
< ncols
; ++col
)
1086 m_colWidths
[ col
] = sz
.x
/ ncols
;
1089 sz
= wxSize( pt
.x
+ sz
.x
, pt
.y
+ sz
.y
);
1092 for (int c
= 0; c
< ncols
; c
++)
1095 for (int r
= 0; r
< nrows
; r
++)
1097 int i
= r
* ncols
+ c
;
1100 wxSizerItemList::Node
*node
= m_children
.Item( i
);
1102 wxASSERT_MSG( node
, _T("Failed to find node") );
1104 int w
= wxMax( 0, wxMin( m_colWidths
[c
], sz
.x
- x
) );
1105 int h
= wxMax( 0, wxMin( m_rowHeights
[r
], sz
.y
- y
) );
1107 SetItemBounds( node
->GetData(), x
, y
, w
, h
);
1109 y
= y
+ m_rowHeights
[r
] + m_vgap
;
1111 x
= x
+ m_colWidths
[c
] + m_hgap
;
1115 wxSize
wxFlexGridSizer::CalcMin()
1121 if ( !CalcRowsCols(nrows
, ncols
) )
1122 return wxSize(10, 10);
1124 // We have to clear the old sizes out if any item has wxADJUST_MINSIZE
1125 // set on it. Its probably quicker to just always do it than test for
1126 // that though. At least do it before resizing the arrays, SetCount will
1127 // initialise new elements to zero.
1128 for( s
= m_rowHeights
.GetCount(), i
= 0; i
< s
; ++i
)
1129 m_rowHeights
[ i
] = 0;
1131 for( s
= m_colWidths
.GetCount(), i
= 0; i
< s
; ++i
)
1132 m_colWidths
[ i
] = 0;
1134 m_rowHeights
.SetCount(nrows
);
1135 m_colWidths
.SetCount(ncols
);
1137 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1142 wxSizerItem
*item
= node
->GetData();
1143 wxSize
sz( item
->CalcMin() );
1144 int row
= i
/ ncols
;
1145 int col
= i
% ncols
;
1147 m_rowHeights
[ row
] = wxMax( sz
.y
, m_rowHeights
[ row
] );
1148 m_colWidths
[ col
] = wxMax( sz
.x
, m_colWidths
[ col
] );
1150 node
= node
->GetNext();
1154 // the logic above works when we resize flexibly in both directions but
1155 // maybe this is not the case
1156 if ( m_flexDirection
!= wxBOTH
)
1158 // select the array corresponding to the direction in which we do *not*
1160 wxArrayInt
& array
= m_flexDirection
== wxVERTICAL
? m_colWidths
1163 const int count
= array
.GetCount();
1165 // find the largest value in this array
1168 for ( n
= 0; n
< count
; ++n
)
1170 if ( array
[n
] > largest
)
1174 // and now fill it with the largest value
1175 for ( n
= 0; n
< count
; ++n
)
1183 for (int col
= 0; col
< ncols
; col
++)
1184 width
+= m_colWidths
[ col
];
1187 for (int row
= 0; row
< nrows
; row
++)
1188 height
+= m_rowHeights
[ row
];
1190 return wxSize( width
+ (ncols
-1) * m_hgap
,
1191 height
+ (nrows
-1) * m_vgap
);
1194 void wxFlexGridSizer::AddGrowableRow( size_t idx
)
1196 m_growableRows
.Add( idx
);
1199 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx
) )
1203 void wxFlexGridSizer::AddGrowableCol( size_t idx
)
1205 m_growableCols
.Add( idx
);
1208 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx
) )
1212 //---------------------------------------------------------------------------
1214 //---------------------------------------------------------------------------
1216 wxBoxSizer::wxBoxSizer( int orient
)
1217 : m_orient( orient
)
1221 void wxBoxSizer::RecalcSizes()
1223 if (m_children
.GetCount() == 0)
1230 if (m_orient
== wxHORIZONTAL
)
1232 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
1233 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
1237 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
1238 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
1242 wxPoint
pt( m_position
);
1244 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1247 wxSizerItem
*item
= node
->GetData();
1249 if (item
->IsShown())
1252 if (item
->GetProportion())
1253 weight
= item
->GetProportion();
1255 wxSize
size( item
->CalcMin() );
1257 if (m_orient
== wxVERTICAL
)
1259 wxCoord height
= size
.y
;
1260 if (item
->GetProportion())
1262 height
= (delta
* weight
) + extra
;
1263 extra
= 0; // only the first item will get the remainder as extra size
1266 wxPoint
child_pos( pt
);
1267 wxSize
child_size( wxSize( size
.x
, height
) );
1269 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1270 child_size
.x
= m_size
.x
;
1271 else if (item
->GetFlag() & wxALIGN_RIGHT
)
1272 child_pos
.x
+= m_size
.x
- size
.x
;
1273 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
1274 // XXX wxCENTER is added for backward compatibility;
1275 // wxALIGN_CENTER should be used in new code
1276 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
1278 item
->SetDimension( child_pos
, child_size
);
1284 wxCoord width
= size
.x
;
1285 if (item
->GetProportion())
1287 width
= (delta
* weight
) + extra
;
1288 extra
= 0; // only the first item will get the remainder as extra size
1291 wxPoint
child_pos( pt
);
1292 wxSize
child_size( wxSize(width
, size
.y
) );
1294 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1295 child_size
.y
= m_size
.y
;
1296 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
1297 child_pos
.y
+= m_size
.y
- size
.y
;
1298 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
1299 // XXX wxCENTER is added for backward compatibility;
1300 // wxALIGN_CENTER should be used in new code
1301 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
1303 item
->SetDimension( child_pos
, child_size
);
1309 node
= node
->GetNext();
1313 wxSize
wxBoxSizer::CalcMin()
1315 if (m_children
.GetCount() == 0)
1316 return wxSize(10,10);
1324 // Find how long each stretch unit needs to be
1325 int stretchSize
= 1;
1326 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1330 wxSizerItem
*item
= node
->GetData();
1332 if (item
->IsShown() && item
->GetProportion() != 0)
1334 int stretch
= item
->GetProportion();
1335 wxSize
size( item
->CalcMin() );
1337 // Integer division rounded up is (a + b - 1) / b
1338 if (m_orient
== wxHORIZONTAL
)
1339 sizePerStretch
= ( size
.x
+ stretch
- 1 ) / stretch
;
1341 sizePerStretch
= ( size
.y
+ stretch
- 1 ) / stretch
;
1342 if (sizePerStretch
> stretchSize
)
1343 stretchSize
= sizePerStretch
;
1345 node
= node
->GetNext();
1348 // Calculate overall minimum size
1349 node
= m_children
.GetFirst();
1352 wxSizerItem
*item
= node
->GetData();
1354 if (item
->IsShown())
1356 m_stretchable
+= item
->GetProportion();
1358 wxSize
size( item
->CalcMin() );
1359 if (item
->GetProportion() != 0)
1361 if (m_orient
== wxHORIZONTAL
)
1362 size
.x
= stretchSize
* item
->GetProportion();
1364 size
.y
= stretchSize
* item
->GetProportion();
1367 if (m_orient
== wxHORIZONTAL
)
1369 m_minWidth
+= size
.x
;
1370 m_minHeight
= wxMax( m_minHeight
, size
.y
);
1374 m_minHeight
+= size
.y
;
1375 m_minWidth
= wxMax( m_minWidth
, size
.x
);
1378 if (item
->GetProportion() == 0)
1380 if (m_orient
== wxVERTICAL
)
1382 m_fixedHeight
+= size
.y
;
1383 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
1387 m_fixedWidth
+= size
.x
;
1388 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
1392 node
= node
->GetNext();
1395 return wxSize( m_minWidth
, m_minHeight
);
1398 //---------------------------------------------------------------------------
1400 //---------------------------------------------------------------------------
1404 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
1405 : wxBoxSizer( orient
)
1406 , m_staticBox( box
)
1408 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
1411 static void GetStaticBoxBorders( wxStaticBox
*box
,
1415 // this has to be done platform by platform as there is no way to
1416 // guess the thickness of a wxStaticBox border
1418 if ( box
->GetLabel().IsEmpty() )
1427 void wxStaticBoxSizer::RecalcSizes()
1429 int top_border
, other_border
;
1430 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1432 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1434 wxPoint
old_pos( m_position
);
1435 m_position
.x
+= other_border
;
1436 m_position
.y
+= top_border
;
1437 wxSize
old_size( m_size
);
1438 m_size
.x
-= 2*other_border
;
1439 m_size
.y
-= top_border
+ other_border
;
1441 wxBoxSizer::RecalcSizes();
1443 m_position
= old_pos
;
1447 wxSize
wxStaticBoxSizer::CalcMin()
1449 int top_border
, other_border
;
1450 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1452 wxSize
ret( wxBoxSizer::CalcMin() );
1453 ret
.x
+= 2*other_border
;
1454 ret
.y
+= other_border
+ top_border
;
1459 #endif // wxUSE_STATBOX
1461 //---------------------------------------------------------------------------
1463 //---------------------------------------------------------------------------
1467 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
1470 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
1473 void wxNotebookSizer::RecalcSizes()
1475 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1478 wxSize
wxNotebookSizer::CalcMin()
1480 wxSize sizeBorder
= m_notebook
->CalcSizeFromPage(wxSize(0, 0));
1485 if (m_notebook
->GetChildren().GetCount() == 0)
1487 return wxSize(sizeBorder
.x
+ 10, sizeBorder
.y
+ 10);
1493 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
1496 wxWindow
*item
= node
->GetData();
1497 wxSizer
*itemsizer
= item
->GetSizer();
1501 wxSize
subsize( itemsizer
->CalcMin() );
1503 if (subsize
.x
> maxX
)
1505 if (subsize
.y
> maxY
)
1509 node
= node
->GetNext();
1512 return wxSize( maxX
, maxY
) + sizeBorder
;
1515 #endif // wxUSE_NOTEBOOK