1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn, contributions by
5 // Dirk Holtwick, Ron Lee
6 // Modified by: Ron Lee
9 // Copyright: (c) Robin Dunn, 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() );
1032 wxArrayInt temp_proportions
;
1033 int sum_proportions
= 0;
1034 int growable_space
= 0;
1036 // what to do with the rows? by default, resize them proportionally
1037 if ( (m_flexDirection
& wxVERTICAL
) ||
1038 (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) )
1040 // Transfer only those rows into temp which exist in the sizer
1041 // ignoring the superfluous ones. This prevents a segfault when
1042 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
1043 for (idx
= 0; idx
< m_growableRows
.GetCount(); idx
++)
1045 if (m_growableRows
[idx
] < nrows
)
1047 temp
.Add( m_growableRows
[idx
] );
1048 temp_proportions
.Add( m_growableRowsProportions
[idx
] );
1049 sum_proportions
+= m_growableRowsProportions
[idx
];
1050 growable_space
+= m_rowHeights
[ temp
[idx
] ];
1054 num
= temp
.GetCount();
1056 if ((num
> 0) && (sz
.y
> minsz
.y
))
1058 for (idx
= 0; idx
< num
; idx
++)
1060 delta
= (sz
.y
- minsz
.y
);
1061 if (sum_proportions
== 0)
1062 delta
= (delta
/num
) + m_rowHeights
[ temp
[idx
] ];
1064 delta
= ((delta
+growable_space
)*temp_proportions
[idx
])/
1066 m_rowHeights
[ temp
[idx
] ] = delta
;
1070 temp_proportions
.Empty();
1071 sum_proportions
= 0;
1074 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.y
> minsz
.y
) )
1076 // rounding problem?
1077 for ( int row
= 0; row
< nrows
; ++row
)
1078 m_rowHeights
[ row
] = sz
.y
/ nrows
;
1081 // the same logic as above but for the columns
1082 if ( (m_flexDirection
& wxHORIZONTAL
) ||
1083 (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) )
1086 for (idx
= 0; idx
< m_growableCols
.GetCount(); idx
++)
1088 if (m_growableCols
[idx
] < ncols
)
1090 temp
.Add( m_growableCols
[idx
] );
1091 temp_proportions
.Add( m_growableColsProportions
[idx
] );
1092 sum_proportions
+= m_growableColsProportions
[idx
];
1093 growable_space
+= m_colWidths
[idx
];
1097 num
= temp
.GetCount();
1099 if ((num
> 0) && (sz
.x
> minsz
.x
))
1101 for (idx
= 0; idx
< num
; idx
++)
1103 delta
= (sz
.x
- minsz
.x
);
1104 if (sum_proportions
== 0)
1105 delta
= (delta
/num
) + m_colWidths
[ temp
[idx
] ];
1107 delta
= ((delta
+growable_space
)*temp_proportions
[idx
])/
1109 m_colWidths
[ temp
[idx
] ] = delta
;
1113 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.x
> minsz
.x
) )
1115 for ( int col
=0; col
< ncols
; ++col
)
1116 m_colWidths
[ col
] = sz
.x
/ ncols
;
1119 sz
= wxSize( pt
.x
+ sz
.x
, pt
.y
+ sz
.y
);
1122 for (int c
= 0; c
< ncols
; c
++)
1125 for (int r
= 0; r
< nrows
; r
++)
1127 int i
= r
* ncols
+ c
;
1130 wxSizerItemList::Node
*node
= m_children
.Item( i
);
1132 wxASSERT_MSG( node
, _T("Failed to find node") );
1134 int w
= wxMax( 0, wxMin( m_colWidths
[c
], sz
.x
- x
) );
1135 int h
= wxMax( 0, wxMin( m_rowHeights
[r
], sz
.y
- y
) );
1137 SetItemBounds( node
->GetData(), x
, y
, w
, h
);
1139 y
= y
+ m_rowHeights
[r
] + m_vgap
;
1141 x
= x
+ m_colWidths
[c
] + m_hgap
;
1145 wxSize
wxFlexGridSizer::CalcMin()
1151 if ( !CalcRowsCols(nrows
, ncols
) )
1152 return wxSize(10, 10);
1154 // We have to clear the old sizes out if any item has wxADJUST_MINSIZE
1155 // set on it. Its probably quicker to just always do it than test for
1156 // that though. At least do it before resizing the arrays, SetCount will
1157 // initialise new elements to zero.
1158 for( s
= m_rowHeights
.GetCount(), i
= 0; i
< s
; ++i
)
1159 m_rowHeights
[ i
] = 0;
1161 for( s
= m_colWidths
.GetCount(), i
= 0; i
< s
; ++i
)
1162 m_colWidths
[ i
] = 0;
1164 m_rowHeights
.SetCount(nrows
);
1165 m_colWidths
.SetCount(ncols
);
1167 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1172 wxSizerItem
*item
= node
->GetData();
1173 wxSize
sz( item
->CalcMin() );
1174 int row
= i
/ ncols
;
1175 int col
= i
% ncols
;
1177 m_rowHeights
[ row
] = wxMax( sz
.y
, m_rowHeights
[ row
] );
1178 m_colWidths
[ col
] = wxMax( sz
.x
, m_colWidths
[ col
] );
1180 node
= node
->GetNext();
1184 // the logic above works when we resize flexibly in both directions but
1185 // maybe this is not the case
1186 if ( m_flexDirection
!= wxBOTH
)
1188 // select the array corresponding to the direction in which we do *not*
1190 wxArrayInt
& array
= m_flexDirection
== wxVERTICAL
? m_colWidths
1193 const int count
= array
.GetCount();
1195 // find the largest value in this array
1198 for ( n
= 0; n
< count
; ++n
)
1200 if ( array
[n
] > largest
)
1204 // and now fill it with the largest value
1205 for ( n
= 0; n
< count
; ++n
)
1213 for (int col
= 0; col
< ncols
; col
++)
1214 width
+= m_colWidths
[ col
];
1217 for (int row
= 0; row
< nrows
; row
++)
1218 height
+= m_rowHeights
[ row
];
1220 return wxSize( width
+ (ncols
-1) * m_hgap
,
1221 height
+ (nrows
-1) * m_vgap
);
1224 void wxFlexGridSizer::AddGrowableRow( size_t idx
, int proportion
)
1226 m_growableRows
.Add( idx
);
1227 m_growableRowsProportions
.Add( proportion
);
1230 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx
) )
1234 void wxFlexGridSizer::AddGrowableCol( size_t idx
, int proportion
)
1236 m_growableCols
.Add( idx
);
1237 m_growableColsProportions
.Add( proportion
);
1240 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx
) )
1244 //---------------------------------------------------------------------------
1246 //---------------------------------------------------------------------------
1248 wxBoxSizer::wxBoxSizer( int orient
)
1249 : m_orient( orient
)
1253 void wxBoxSizer::RecalcSizes()
1255 if (m_children
.GetCount() == 0)
1262 if (m_orient
== wxHORIZONTAL
)
1264 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
1265 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
1269 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
1270 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
1274 wxPoint
pt( m_position
);
1276 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1279 wxSizerItem
*item
= node
->GetData();
1281 if (item
->IsShown())
1284 if (item
->GetProportion())
1285 weight
= item
->GetProportion();
1287 wxSize
size( item
->CalcMin() );
1289 if (m_orient
== wxVERTICAL
)
1291 wxCoord height
= size
.y
;
1292 if (item
->GetProportion())
1294 height
= (delta
* weight
) + extra
;
1295 extra
= 0; // only the first item will get the remainder as extra size
1298 wxPoint
child_pos( pt
);
1299 wxSize
child_size( wxSize( size
.x
, height
) );
1301 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1302 child_size
.x
= m_size
.x
;
1303 else if (item
->GetFlag() & wxALIGN_RIGHT
)
1304 child_pos
.x
+= m_size
.x
- size
.x
;
1305 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
1306 // XXX wxCENTER is added for backward compatibility;
1307 // wxALIGN_CENTER should be used in new code
1308 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
1310 item
->SetDimension( child_pos
, child_size
);
1316 wxCoord width
= size
.x
;
1317 if (item
->GetProportion())
1319 width
= (delta
* weight
) + extra
;
1320 extra
= 0; // only the first item will get the remainder as extra size
1323 wxPoint
child_pos( pt
);
1324 wxSize
child_size( wxSize(width
, size
.y
) );
1326 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1327 child_size
.y
= m_size
.y
;
1328 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
1329 child_pos
.y
+= m_size
.y
- size
.y
;
1330 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
1331 // XXX wxCENTER is added for backward compatibility;
1332 // wxALIGN_CENTER should be used in new code
1333 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
1335 item
->SetDimension( child_pos
, child_size
);
1341 node
= node
->GetNext();
1345 wxSize
wxBoxSizer::CalcMin()
1347 if (m_children
.GetCount() == 0)
1348 return wxSize(10,10);
1356 // Find how long each stretch unit needs to be
1357 int stretchSize
= 1;
1358 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1362 wxSizerItem
*item
= node
->GetData();
1364 if (item
->IsShown() && item
->GetProportion() != 0)
1366 int stretch
= item
->GetProportion();
1367 wxSize
size( item
->CalcMin() );
1369 // Integer division rounded up is (a + b - 1) / b
1370 if (m_orient
== wxHORIZONTAL
)
1371 sizePerStretch
= ( size
.x
+ stretch
- 1 ) / stretch
;
1373 sizePerStretch
= ( size
.y
+ stretch
- 1 ) / stretch
;
1374 if (sizePerStretch
> stretchSize
)
1375 stretchSize
= sizePerStretch
;
1377 node
= node
->GetNext();
1380 // Calculate overall minimum size
1381 node
= m_children
.GetFirst();
1384 wxSizerItem
*item
= node
->GetData();
1386 if (item
->IsShown())
1388 m_stretchable
+= item
->GetProportion();
1390 wxSize
size( item
->CalcMin() );
1391 if (item
->GetProportion() != 0)
1393 if (m_orient
== wxHORIZONTAL
)
1394 size
.x
= stretchSize
* item
->GetProportion();
1396 size
.y
= stretchSize
* item
->GetProportion();
1399 if (m_orient
== wxHORIZONTAL
)
1401 m_minWidth
+= size
.x
;
1402 m_minHeight
= wxMax( m_minHeight
, size
.y
);
1406 m_minHeight
+= size
.y
;
1407 m_minWidth
= wxMax( m_minWidth
, size
.x
);
1410 if (item
->GetProportion() == 0)
1412 if (m_orient
== wxVERTICAL
)
1414 m_fixedHeight
+= size
.y
;
1415 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
1419 m_fixedWidth
+= size
.x
;
1420 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
1424 node
= node
->GetNext();
1427 return wxSize( m_minWidth
, m_minHeight
);
1430 //---------------------------------------------------------------------------
1432 //---------------------------------------------------------------------------
1436 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
1437 : wxBoxSizer( orient
)
1438 , m_staticBox( box
)
1440 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
1443 static void GetStaticBoxBorders( wxStaticBox
*box
,
1447 // this has to be done platform by platform as there is no way to
1448 // guess the thickness of a wxStaticBox border
1450 if ( box
->GetLabel().IsEmpty() )
1454 *borderTop
= box
->GetCharHeight();
1459 void wxStaticBoxSizer::RecalcSizes()
1461 int top_border
, other_border
;
1462 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1464 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1466 wxPoint
old_pos( m_position
);
1467 m_position
.x
+= other_border
;
1468 m_position
.y
+= top_border
;
1469 wxSize
old_size( m_size
);
1470 m_size
.x
-= 2*other_border
;
1471 m_size
.y
-= top_border
+ other_border
;
1473 wxBoxSizer::RecalcSizes();
1475 m_position
= old_pos
;
1479 wxSize
wxStaticBoxSizer::CalcMin()
1481 int top_border
, other_border
;
1482 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1484 wxSize
ret( wxBoxSizer::CalcMin() );
1485 ret
.x
+= 2*other_border
;
1486 ret
.y
+= other_border
+ top_border
;
1491 #endif // wxUSE_STATBOX
1493 //---------------------------------------------------------------------------
1495 //---------------------------------------------------------------------------
1499 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
1502 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
1505 void wxNotebookSizer::RecalcSizes()
1507 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1510 wxSize
wxNotebookSizer::CalcMin()
1512 wxSize sizeBorder
= m_notebook
->CalcSizeFromPage(wxSize(0, 0));
1517 if (m_notebook
->GetChildren().GetCount() == 0)
1519 return wxSize(sizeBorder
.x
+ 10, sizeBorder
.y
+ 10);
1525 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
1528 wxWindow
*item
= node
->GetData();
1529 wxSizer
*itemsizer
= item
->GetSizer();
1533 wxSize
subsize( itemsizer
->CalcMin() );
1535 if (subsize
.x
> maxX
)
1537 if (subsize
.y
> maxY
)
1541 node
= node
->GetNext();
1544 return wxSize( maxX
, maxY
) + sizeBorder
;
1547 #endif // wxUSE_NOTEBOOK