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() );
1030 // what to do with the rows? by default, resize them proportionally
1031 if ( sz
.y
> minsz
.y
&& ( (m_flexDirection
& wxVERTICAL
) || (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) ) )
1033 int sum_proportions
= 0;
1034 int growable_space
= 0;
1037 for (idx
= 0; idx
< m_growableRows
.GetCount(); idx
++)
1039 // Since the number of rows/columns can change as items are inserted/deleted, we need
1040 // to verify at runtime that the requested growable rows/columns are still valid.
1041 if (m_growableRows
[idx
] >= nrows
)
1043 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1044 // This causes the row/column to be hidden completely.
1045 if (m_rowHeights
[ m_growableRows
[idx
] ] == -1)
1047 sum_proportions
+= m_growableRowsProportions
[idx
];
1048 growable_space
+= m_rowHeights
[ m_growableRows
[idx
] ];
1054 for (idx
= 0; idx
< m_growableRows
.GetCount(); idx
++)
1056 if (m_growableRows
[idx
] >= nrows
)
1058 if (m_rowHeights
[ m_growableRows
[idx
] ] == -1)
1059 m_rowHeights
[ m_growableRows
[idx
] ] = 0;
1062 int delta
= (sz
.y
- minsz
.y
);
1063 if (sum_proportions
== 0)
1064 delta
= (delta
/num
) + m_rowHeights
[ m_growableRows
[idx
] ];
1066 delta
= ((delta
+growable_space
)*m_growableRowsProportions
[idx
]) / sum_proportions
;
1067 m_rowHeights
[ m_growableRows
[idx
] ] = delta
;
1072 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.y
> minsz
.y
) )
1074 // rounding problem?
1075 for ( int row
= 0; row
< nrows
; ++row
)
1076 m_rowHeights
[ row
] = sz
.y
/ nrows
;
1079 // the same logic as above but for the columns
1080 if ( sz
.x
> minsz
.x
&& ( (m_flexDirection
& wxHORIZONTAL
) || (m_growMode
== wxFLEX_GROWMODE_SPECIFIED
) ) )
1082 int sum_proportions
= 0;
1083 int growable_space
= 0;
1086 for (idx
= 0; idx
< m_growableCols
.GetCount(); idx
++)
1088 // Since the number of rows/columns can change as items are inserted/deleted, we need
1089 // to verify at runtime that the requested growable rows/columns are still valid.
1090 if (m_growableCols
[idx
] >= ncols
)
1092 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1093 // This causes the column to be hidden completely.
1094 if (m_colWidths
[ m_growableCols
[idx
] ] == -1)
1096 sum_proportions
+= m_growableColsProportions
[idx
];
1097 // wtb 5/12/02 bugfix - was m_ColWidths[idx]!!
1098 growable_space
+= m_colWidths
[ m_growableCols
[idx
] ];
1104 for (idx
= 0; idx
< m_growableCols
.GetCount(); idx
++)
1106 if (m_growableCols
[idx
] >= ncols
)
1108 if (m_colWidths
[ m_growableCols
[idx
] ] == -1)
1109 m_colWidths
[ m_growableCols
[idx
] ] = 0;
1112 int delta
= (sz
.x
- minsz
.x
);
1113 if (sum_proportions
== 0)
1114 delta
= (delta
/num
) + m_colWidths
[ m_growableCols
[idx
] ];
1116 delta
= ((delta
+growable_space
)*m_growableColsProportions
[idx
])/sum_proportions
;
1117 m_colWidths
[ m_growableCols
[idx
] ] = delta
;
1122 else if ( (m_growMode
== wxFLEX_GROWMODE_ALL
) && (sz
.x
> minsz
.x
) )
1124 for ( int col
=0; col
< ncols
; ++col
)
1125 m_colWidths
[ col
] = sz
.x
/ ncols
;
1128 sz
= wxSize( pt
.x
+ sz
.x
, pt
.y
+ sz
.y
);
1131 for (int c
= 0; c
< ncols
; c
++)
1134 for (int r
= 0; r
< nrows
; r
++)
1136 int i
= r
* ncols
+ c
;
1139 wxSizerItemList::Node
*node
= m_children
.Item( i
);
1141 wxASSERT_MSG( node
, _T("Failed to find node") );
1143 int w
= wxMax( 0, wxMin( m_colWidths
[c
], sz
.x
- x
) );
1144 int h
= wxMax( 0, wxMin( m_rowHeights
[r
], sz
.y
- y
) );
1146 SetItemBounds( node
->GetData(), x
, y
, w
, h
);
1148 y
= y
+ m_rowHeights
[r
] + m_vgap
;
1150 x
= x
+ m_colWidths
[c
] + m_hgap
;
1154 wxSize
wxFlexGridSizer::CalcMin()
1160 // Number of rows/columns can change as items are added or removed.
1161 if ( !CalcRowsCols(nrows
, ncols
) )
1162 return wxSize(10, 10);
1164 m_rowHeights
.SetCount(nrows
);
1165 m_colWidths
.SetCount(ncols
);
1167 // We have to recalcuate the sizes in case an item has wxADJUST_MINSIZE, has changed
1168 // minimum size since the previous layout, or has been hidden using wxSizer::Show().
1169 // If all the items in a row/column are hidden, the final dimension of the row/column
1170 // will be -1, indicating that the column itself is hidden.
1171 for( s
= m_rowHeights
.GetCount(), i
= 0; i
< s
; ++i
)
1172 m_rowHeights
[ i
] = -1;
1173 for( s
= m_colWidths
.GetCount(), i
= 0; i
< s
; ++i
)
1174 m_colWidths
[ i
] = -1;
1176 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1181 wxSizerItem
*item
= node
->GetData();
1182 if ( item
->IsShown() )
1184 wxSize
sz( item
->CalcMin() );
1185 int row
= i
/ ncols
;
1186 int col
= i
% ncols
;
1188 m_rowHeights
[ row
] = wxMax( wxMax( 0, sz
.y
), m_rowHeights
[ row
] );
1189 m_colWidths
[ col
] = wxMax( wxMax( 0, sz
.x
), m_colWidths
[ col
] );
1192 node
= node
->GetNext();
1196 // the logic above works when we resize flexibly in both directions but
1197 // maybe this is not the case
1198 if ( m_flexDirection
!= wxBOTH
)
1200 // select the array corresponding to the direction in which we do *not*
1202 wxArrayInt
& array
= m_flexDirection
== wxVERTICAL
? m_colWidths
1205 const int count
= array
.GetCount();
1207 // find the largest value in this array
1209 for ( n
= 0; n
< count
; ++n
)
1211 if ( array
[n
] > largest
)
1215 // and now fill it with the largest value
1216 for ( n
= 0; n
< count
; ++n
)
1222 // Sum total minimum size, including gaps between rows/columns.
1223 // -1 is used as a magic number meaning empty column.
1225 for (int col
= 0; col
< ncols
; col
++)
1226 if ( m_colWidths
[ col
] != -1 )
1227 width
+= m_colWidths
[ col
] + ( col
== ncols
-1 ? 0 : m_hgap
);
1230 for (int row
= 0; row
< nrows
; row
++)
1231 if ( m_rowHeights
[ row
] != -1 )
1232 height
+= m_rowHeights
[ row
] + ( row
== nrows
-1 ? 0 : m_vgap
);
1234 return wxSize( width
, height
);
1237 void wxFlexGridSizer::AddGrowableRow( size_t idx
, int proportion
)
1239 m_growableRows
.Add( idx
);
1240 m_growableRowsProportions
.Add( proportion
);
1243 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx
) )
1247 void wxFlexGridSizer::AddGrowableCol( size_t idx
, int proportion
)
1249 m_growableCols
.Add( idx
);
1250 m_growableColsProportions
.Add( proportion
);
1253 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx
) )
1257 //---------------------------------------------------------------------------
1259 //---------------------------------------------------------------------------
1261 wxBoxSizer::wxBoxSizer( int orient
)
1262 : m_orient( orient
)
1266 void wxBoxSizer::RecalcSizes()
1268 if (m_children
.GetCount() == 0)
1275 if (m_orient
== wxHORIZONTAL
)
1277 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
1278 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
1282 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
1283 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
1287 wxPoint
pt( m_position
);
1289 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1292 wxSizerItem
*item
= node
->GetData();
1294 if (item
->IsShown())
1297 if (item
->GetProportion())
1298 weight
= item
->GetProportion();
1300 wxSize
size( item
->CalcMin() );
1302 if (m_orient
== wxVERTICAL
)
1304 wxCoord height
= size
.y
;
1305 if (item
->GetProportion())
1307 height
= (delta
* weight
) + extra
;
1308 extra
= 0; // only the first item will get the remainder as extra size
1311 wxPoint
child_pos( pt
);
1312 wxSize
child_size( wxSize( size
.x
, height
) );
1314 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1315 child_size
.x
= m_size
.x
;
1316 else if (item
->GetFlag() & wxALIGN_RIGHT
)
1317 child_pos
.x
+= m_size
.x
- size
.x
;
1318 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
1319 // XXX wxCENTER is added for backward compatibility;
1320 // wxALIGN_CENTER should be used in new code
1321 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
1323 item
->SetDimension( child_pos
, child_size
);
1329 wxCoord width
= size
.x
;
1330 if (item
->GetProportion())
1332 width
= (delta
* weight
) + extra
;
1333 extra
= 0; // only the first item will get the remainder as extra size
1336 wxPoint
child_pos( pt
);
1337 wxSize
child_size( wxSize(width
, size
.y
) );
1339 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
1340 child_size
.y
= m_size
.y
;
1341 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
1342 child_pos
.y
+= m_size
.y
- size
.y
;
1343 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
1344 // XXX wxCENTER is added for backward compatibility;
1345 // wxALIGN_CENTER should be used in new code
1346 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
1348 item
->SetDimension( child_pos
, child_size
);
1354 node
= node
->GetNext();
1358 wxSize
wxBoxSizer::CalcMin()
1360 if (m_children
.GetCount() == 0)
1361 return wxSize(10,10);
1369 // Find how long each stretch unit needs to be
1370 int stretchSize
= 1;
1371 wxSizerItemList::Node
*node
= m_children
.GetFirst();
1375 wxSizerItem
*item
= node
->GetData();
1377 if (item
->IsShown() && item
->GetProportion() != 0)
1379 int stretch
= item
->GetProportion();
1380 wxSize
size( item
->CalcMin() );
1382 // Integer division rounded up is (a + b - 1) / b
1383 if (m_orient
== wxHORIZONTAL
)
1384 sizePerStretch
= ( size
.x
+ stretch
- 1 ) / stretch
;
1386 sizePerStretch
= ( size
.y
+ stretch
- 1 ) / stretch
;
1387 if (sizePerStretch
> stretchSize
)
1388 stretchSize
= sizePerStretch
;
1390 node
= node
->GetNext();
1393 // Calculate overall minimum size
1394 node
= m_children
.GetFirst();
1397 wxSizerItem
*item
= node
->GetData();
1399 if (item
->IsShown())
1401 m_stretchable
+= item
->GetProportion();
1403 wxSize
size( item
->CalcMin() );
1404 if (item
->GetProportion() != 0)
1406 if (m_orient
== wxHORIZONTAL
)
1407 size
.x
= stretchSize
* item
->GetProportion();
1409 size
.y
= stretchSize
* item
->GetProportion();
1412 if (m_orient
== wxHORIZONTAL
)
1414 m_minWidth
+= size
.x
;
1415 m_minHeight
= wxMax( m_minHeight
, size
.y
);
1419 m_minHeight
+= size
.y
;
1420 m_minWidth
= wxMax( m_minWidth
, size
.x
);
1423 if (item
->GetProportion() == 0)
1425 if (m_orient
== wxVERTICAL
)
1427 m_fixedHeight
+= size
.y
;
1428 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
1432 m_fixedWidth
+= size
.x
;
1433 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
1437 node
= node
->GetNext();
1440 return wxSize( m_minWidth
, m_minHeight
);
1443 //---------------------------------------------------------------------------
1445 //---------------------------------------------------------------------------
1449 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
1450 : wxBoxSizer( orient
)
1451 , m_staticBox( box
)
1453 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
1456 static void GetStaticBoxBorders( wxStaticBox
*box
,
1460 // this has to be done platform by platform as there is no way to
1461 // guess the thickness of a wxStaticBox border
1463 box
->GetBordersForSizer(borderTop
,borderOther
);
1464 #else // __WXCOCOA__
1466 if ( box
->GetLabel().IsEmpty() )
1470 *borderTop
= box
->GetCharHeight();
1473 #endif // __WXCOCOA__
1476 void wxStaticBoxSizer::RecalcSizes()
1478 int top_border
, other_border
;
1479 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1481 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1483 wxPoint
old_pos( m_position
);
1484 m_position
.x
+= other_border
;
1485 m_position
.y
+= top_border
;
1486 wxSize
old_size( m_size
);
1487 m_size
.x
-= 2*other_border
;
1488 m_size
.y
-= top_border
+ other_border
;
1490 wxBoxSizer::RecalcSizes();
1492 m_position
= old_pos
;
1496 wxSize
wxStaticBoxSizer::CalcMin()
1498 int top_border
, other_border
;
1499 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
1501 wxSize
ret( wxBoxSizer::CalcMin() );
1502 ret
.x
+= 2*other_border
;
1503 ret
.y
+= other_border
+ top_border
;
1508 #endif // wxUSE_STATBOX
1510 //---------------------------------------------------------------------------
1512 //---------------------------------------------------------------------------
1516 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
1519 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
1522 void wxNotebookSizer::RecalcSizes()
1524 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
1527 wxSize
wxNotebookSizer::CalcMin()
1529 wxSize sizeBorder
= m_notebook
->CalcSizeFromPage(wxSize(0, 0));
1534 if (m_notebook
->GetChildren().GetCount() == 0)
1536 return wxSize(sizeBorder
.x
+ 10, sizeBorder
.y
+ 10);
1542 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
1545 wxWindow
*item
= node
->GetData();
1546 wxSizer
*itemsizer
= item
->GetSizer();
1550 wxSize
subsize( itemsizer
->CalcMin() );
1552 if (subsize
.x
> maxX
)
1554 if (subsize
.y
> maxY
)
1558 node
= node
->GetNext();
1561 return wxSize( maxX
, maxY
) + sizeBorder
;
1564 #endif // wxUSE_NOTEBOOK