1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/sizer.cpp
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 /////////////////////////////////////////////////////////////////////////////
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
20 #include "wx/display.h"
24 #include "wx/string.h"
28 #include "wx/settings.h"
29 #include "wx/button.h"
30 #include "wx/statbox.h"
31 #include "wx/toplevel.h"
34 #include "wx/listimpl.cpp"
37 //---------------------------------------------------------------------------
39 IMPLEMENT_CLASS(wxSizerItem
, wxObject
)
40 IMPLEMENT_CLASS(wxSizer
, wxObject
)
41 IMPLEMENT_CLASS(wxGridSizer
, wxSizer
)
42 IMPLEMENT_CLASS(wxFlexGridSizer
, wxGridSizer
)
43 IMPLEMENT_CLASS(wxBoxSizer
, wxSizer
)
45 IMPLEMENT_CLASS(wxStaticBoxSizer
, wxBoxSizer
)
48 IMPLEMENT_CLASS(wxStdDialogButtonSizer
, wxBoxSizer
)
51 WX_DEFINE_EXPORTED_LIST( wxSizerItemList
)
86 // ----------------------------------------------------------------------------
88 // ----------------------------------------------------------------------------
90 void wxSizerItem::Init(const wxSizerFlags
& flags
)
94 m_proportion
= flags
.GetProportion();
95 m_flag
= flags
.GetFlags();
96 m_border
= flags
.GetBorderInPixels();
99 wxSizerItem::wxSizerItem()
110 void wxSizerItem::DoSetWindow(wxWindow
*window
)
112 wxCHECK_RET( window
, _T("NULL window in wxSizerItem::SetWindow()") );
114 m_kind
= Item_Window
;
117 // window doesn't become smaller than its initial size, whatever happens
118 m_minSize
= window
->GetSize();
120 if ( m_flag
& wxFIXED_MINSIZE
)
121 window
->SetMinSize(m_minSize
);
123 // aspect ratio calculated from initial size
127 wxSizerItem::wxSizerItem(wxWindow
*window
,
133 m_proportion(proportion
),
143 void wxSizerItem::DoSetSizer(wxSizer
*sizer
)
149 wxSizerItem::wxSizerItem(wxSizer
*sizer
,
156 m_proportion(proportion
),
165 // m_minSize is set later
169 void wxSizerItem::DoSetSpacer(const wxSize
& size
)
171 m_kind
= Item_Spacer
;
172 m_spacer
= new wxSizerSpacer(size
);
177 wxSizerItem::wxSizerItem(int width
,
185 m_minSize(width
, height
), // minimal size is the initial size
186 m_proportion(proportion
),
192 DoSetSpacer(wxSize(width
, height
));
195 wxSizerItem::~wxSizerItem()
201 void wxSizerItem::Free()
209 m_window
->SetContainingSizer(NULL
);
222 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
228 wxSize
wxSizerItem::GetSpacer() const
231 if ( m_kind
== Item_Spacer
)
232 size
= m_spacer
->GetSize();
238 wxSize
wxSizerItem::GetSize() const
247 ret
= m_window
->GetSize();
251 ret
= m_sizer
->GetSize();
255 ret
= m_spacer
->GetSize();
260 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
267 if (m_flag
& wxNORTH
)
269 if (m_flag
& wxSOUTH
)
275 bool wxSizerItem::InformFirstDirection(int direction
, int size
, int availableOtherDir
)
277 // The size that come here will be including borders. Child items should get it
281 if( direction
==wxHORIZONTAL
)
288 else if( direction
==wxVERTICAL
)
290 if (m_flag
& wxNORTH
)
292 if (m_flag
& wxSOUTH
)
298 // Pass the information along to the held object
301 didUse
= GetSizer()->InformFirstDirection(direction
,size
,availableOtherDir
);
303 m_minSize
= GetSizer()->CalcMin();
307 didUse
= GetWindow()->InformFirstDirection(direction
,size
,availableOtherDir
);
309 m_minSize
= m_window
->GetEffectiveMinSize();
311 // This information is useful for items with wxSHAPED flag, since
312 // we can request an optimal min size for such an item. Even if
313 // we overwrite the m_minSize member here, we can read it back from
314 // the owned window (happens automatically).
315 if( (m_flag
& wxSHAPED
) && (m_flag
& wxEXPAND
) && direction
)
317 if( !wxIsNullDouble(m_ratio
) )
319 wxCHECK_MSG( (m_proportion
==0), false, _T("Shaped item, non-zero proportion in wxSizerItem::InformFirstDirection()") );
320 if( direction
==wxHORIZONTAL
&& !wxIsNullDouble(m_ratio
) )
322 // Clip size so that we don't take too much
323 if( availableOtherDir
>=0 && int(size
/m_ratio
)-m_minSize
.y
>availableOtherDir
)
324 size
= int((availableOtherDir
+m_minSize
.y
)*m_ratio
);
325 m_minSize
= wxSize(size
,int(size
/m_ratio
));
327 else if( direction
==wxVERTICAL
)
329 // Clip size so that we don't take too much
330 if( availableOtherDir
>=0 && int(size
*m_ratio
)-m_minSize
.x
>availableOtherDir
)
331 size
= int((availableOtherDir
+m_minSize
.x
)/m_ratio
);
332 m_minSize
= wxSize(int(size
*m_ratio
),size
);
342 wxSize
wxSizerItem::CalcMin()
346 m_minSize
= m_sizer
->GetMinSize();
348 // if we have to preserve aspect ratio _AND_ this is
349 // the first-time calculation, consider ret to be initial size
350 if ( (m_flag
& wxSHAPED
) && wxIsNullDouble(m_ratio
) )
353 else if ( IsWindow() )
355 // Since the size of the window may change during runtime, we
356 // should use the current minimal/best size.
357 m_minSize
= m_window
->GetEffectiveMinSize();
360 return GetMinSizeWithBorder();
363 wxSize
wxSizerItem::GetMinSizeWithBorder() const
365 wxSize ret
= m_minSize
;
371 if (m_flag
& wxNORTH
)
373 if (m_flag
& wxSOUTH
)
380 void wxSizerItem::SetDimension( const wxPoint
& pos_
, const wxSize
& size_
)
384 if (m_flag
& wxSHAPED
)
386 // adjust aspect ratio
387 int rwidth
= (int) (size
.y
* m_ratio
);
391 int rheight
= (int) (size
.x
/ m_ratio
);
392 // add vertical space
393 if (m_flag
& wxALIGN_CENTER_VERTICAL
)
394 pos
.y
+= (size
.y
- rheight
) / 2;
395 else if (m_flag
& wxALIGN_BOTTOM
)
396 pos
.y
+= (size
.y
- rheight
);
397 // use reduced dimensions
400 else if (rwidth
< size
.x
)
402 // add horizontal space
403 if (m_flag
& wxALIGN_CENTER_HORIZONTAL
)
404 pos
.x
+= (size
.x
- rwidth
) / 2;
405 else if (m_flag
& wxALIGN_RIGHT
)
406 pos
.x
+= (size
.x
- rwidth
);
411 // This is what GetPosition() returns. Since we calculate
412 // borders afterwards, GetPosition() will be the left/top
413 // corner of the surrounding border.
425 if (m_flag
& wxNORTH
)
430 if (m_flag
& wxSOUTH
)
440 m_rect
= wxRect(pos
, size
);
445 wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
449 m_window
->SetSize(pos
.x
, pos
.y
, size
.x
, size
.y
,
450 wxSIZE_ALLOW_MINUS_ONE
);
454 m_sizer
->SetDimension(pos
.x
, pos
.y
, size
.x
, size
.y
);
458 m_spacer
->SetSize(size
);
463 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
467 void wxSizerItem::DeleteWindows()
476 //We are deleting the window from this sizer - normally
477 //the window destroys the sizer associated with it,
478 //which might destroy this, which we don't want
479 m_window
->SetContainingSizer(NULL
);
481 //Putting this after the switch will result in a spacer
482 //not being deleted properly on destruction
487 m_sizer
->DeleteWindows();
492 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
497 void wxSizerItem::Show( bool show
)
502 wxFAIL_MSG( _T("can't show uninitialized sizer item") );
506 m_window
->Show(show
);
514 m_spacer
->Show(show
);
519 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
523 bool wxSizerItem::IsShown() const
525 if ( m_flag
& wxRESERVE_SPACE_EVEN_IF_HIDDEN
)
531 // we may be called from CalcMin(), just return false so that we're
536 return m_window
->IsShown();
539 // arbitrarily decide that if at least one of our elements is
540 // shown, so are we (this arbitrariness is the reason for
541 // deprecating this function)
543 // Some apps (such as dialog editors) depend on an empty sizer still
544 // being laid out correctly and reporting the correct size and position.
545 if (m_sizer
->GetChildren().GetCount() == 0)
548 for ( wxSizerItemList::compatibility_iterator
549 node
= m_sizer
->GetChildren().GetFirst();
551 node
= node
->GetNext() )
553 if ( node
->GetData()->IsShown() )
560 return m_spacer
->IsShown();
564 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
570 #if WXWIN_COMPATIBILITY_2_6
571 void wxSizerItem::SetOption( int option
)
573 SetProportion( option
);
576 int wxSizerItem::GetOption() const
578 return GetProportion();
580 #endif // WXWIN_COMPATIBILITY_2_6
583 //---------------------------------------------------------------------------
585 //---------------------------------------------------------------------------
589 WX_CLEAR_LIST(wxSizerItemList
, m_children
);
592 wxSizerItem
* wxSizer::Insert( size_t index
, wxSizerItem
*item
)
594 m_children
.Insert( index
, item
);
596 if ( item
->GetWindow() )
597 item
->GetWindow()->SetContainingSizer( this );
599 if ( item
->GetSizer() )
600 item
->GetSizer()->SetContainingWindow( m_containingWindow
);
605 void wxSizer::SetContainingWindow(wxWindow
*win
)
607 if ( win
== m_containingWindow
)
610 m_containingWindow
= win
;
612 // set the same window for all nested sizers as well, they also are in the
614 for ( wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
616 node
= node
->GetNext() )
618 wxSizerItem
*const item
= node
->GetData();
619 wxSizer
*const sizer
= item
->GetSizer();
623 sizer
->SetContainingWindow(win
);
628 #if WXWIN_COMPATIBILITY_2_6
629 bool wxSizer::Remove( wxWindow
*window
)
631 return Detach( window
);
633 #endif // WXWIN_COMPATIBILITY_2_6
635 bool wxSizer::Remove( wxSizer
*sizer
)
637 wxASSERT_MSG( sizer
, _T("Removing NULL sizer") );
639 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
642 wxSizerItem
*item
= node
->GetData();
644 if (item
->GetSizer() == sizer
)
647 m_children
.Erase( node
);
651 node
= node
->GetNext();
657 bool wxSizer::Remove( int index
)
659 wxCHECK_MSG( index
>= 0 && (size_t)index
< m_children
.GetCount(),
661 _T("Remove index is out of range") );
663 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
665 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
667 delete node
->GetData();
668 m_children
.Erase( node
);
673 bool wxSizer::Detach( wxSizer
*sizer
)
675 wxASSERT_MSG( sizer
, _T("Detaching NULL sizer") );
677 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
680 wxSizerItem
*item
= node
->GetData();
682 if (item
->GetSizer() == sizer
)
686 m_children
.Erase( node
);
689 node
= node
->GetNext();
695 bool wxSizer::Detach( wxWindow
*window
)
697 wxASSERT_MSG( window
, _T("Detaching NULL window") );
699 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
702 wxSizerItem
*item
= node
->GetData();
704 if (item
->GetWindow() == window
)
707 m_children
.Erase( node
);
710 node
= node
->GetNext();
716 bool wxSizer::Detach( int index
)
718 wxCHECK_MSG( index
>= 0 && (size_t)index
< m_children
.GetCount(),
720 _T("Detach index is out of range") );
722 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
724 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
726 wxSizerItem
*item
= node
->GetData();
728 if ( item
->IsSizer() )
732 m_children
.Erase( node
);
736 bool wxSizer::Replace( wxWindow
*oldwin
, wxWindow
*newwin
, bool recursive
)
738 wxASSERT_MSG( oldwin
, _T("Replacing NULL window") );
739 wxASSERT_MSG( newwin
, _T("Replacing with NULL window") );
741 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
744 wxSizerItem
*item
= node
->GetData();
746 if (item
->GetWindow() == oldwin
)
748 item
->AssignWindow(newwin
);
749 newwin
->SetContainingSizer( this );
752 else if (recursive
&& item
->IsSizer())
754 if (item
->GetSizer()->Replace( oldwin
, newwin
, true ))
758 node
= node
->GetNext();
764 bool wxSizer::Replace( wxSizer
*oldsz
, wxSizer
*newsz
, bool recursive
)
766 wxASSERT_MSG( oldsz
, _T("Replacing NULL sizer") );
767 wxASSERT_MSG( newsz
, _T("Replacing with NULL sizer") );
769 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
772 wxSizerItem
*item
= node
->GetData();
774 if (item
->GetSizer() == oldsz
)
776 item
->AssignSizer(newsz
);
779 else if (recursive
&& item
->IsSizer())
781 if (item
->GetSizer()->Replace( oldsz
, newsz
, true ))
785 node
= node
->GetNext();
791 bool wxSizer::Replace( size_t old
, wxSizerItem
*newitem
)
793 wxCHECK_MSG( old
< m_children
.GetCount(), false, _T("Replace index is out of range") );
794 wxASSERT_MSG( newitem
, _T("Replacing with NULL item") );
796 wxSizerItemList::compatibility_iterator node
= m_children
.Item( old
);
798 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
800 wxSizerItem
*item
= node
->GetData();
801 node
->SetData(newitem
);
807 void wxSizer::Clear( bool delete_windows
)
809 // First clear the ContainingSizer pointers
810 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
813 wxSizerItem
*item
= node
->GetData();
815 if (item
->IsWindow())
816 item
->GetWindow()->SetContainingSizer( NULL
);
817 node
= node
->GetNext();
820 // Destroy the windows if needed
824 // Now empty the list
825 WX_CLEAR_LIST(wxSizerItemList
, m_children
);
828 void wxSizer::DeleteWindows()
830 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
833 wxSizerItem
*item
= node
->GetData();
835 item
->DeleteWindows();
836 node
= node
->GetNext();
840 wxSize
wxSizer::ComputeFittingClientSize(wxWindow
*window
)
842 wxCHECK_MSG( window
, wxDefaultSize
, "window can't be NULL" );
844 // take the min size by default and limit it by max size
845 wxSize size
= GetMinClientSize(window
);
848 wxTopLevelWindow
*tlw
= wxDynamicCast(window
, wxTopLevelWindow
);
851 // hack for small screen devices where TLWs are always full screen
852 if ( tlw
->IsAlwaysMaximized() )
854 return tlw
->GetClientSize();
857 // limit the window to the size of the display it is on
858 int disp
= wxDisplay::GetFromWindow(window
);
859 if ( disp
== wxNOT_FOUND
)
861 // or, if we don't know which one it is, of the main one
865 sizeMax
= wxDisplay(disp
).GetClientArea().GetSize();
867 // space for decorations and toolbars etc.
868 sizeMax
= tlw
->WindowToClientSize(sizeMax
);
872 sizeMax
= GetMaxClientSize(window
);
875 if ( sizeMax
.x
!= wxDefaultCoord
&& size
.x
> sizeMax
.x
)
877 if ( sizeMax
.y
!= wxDefaultCoord
&& size
.y
> sizeMax
.y
)
883 wxSize
wxSizer::ComputeFittingWindowSize(wxWindow
*window
)
885 wxCHECK_MSG( window
, wxDefaultSize
, "window can't be NULL" );
887 return window
->ClientToWindowSize(ComputeFittingClientSize(window
));
890 wxSize
wxSizer::Fit( wxWindow
*window
)
892 wxCHECK_MSG( window
, wxDefaultSize
, "window can't be NULL" );
895 window
->SetClientSize(ComputeFittingClientSize(window
));
897 // return entire size
898 return window
->GetSize();
901 void wxSizer::FitInside( wxWindow
*window
)
904 if (window
->IsTopLevel())
905 size
= VirtualFitSize( window
);
907 size
= GetMinClientSize( window
);
909 window
->SetVirtualSize( size
);
912 void wxSizer::Layout()
914 // (re)calculates minimums needed for each item and other preparations
918 // Applies the layout and repositions/resizes the items
922 void wxSizer::SetSizeHints( wxWindow
*window
)
924 // Preserve the window's max size hints, but set the
925 // lower bound according to the sizer calculations.
927 // This is equivalent to calling Fit(), except that we need to set
928 // the size hints _in between_ the two steps performed by Fit
929 // (1. ComputeFittingClientSize, 2. SetClientSize). That's because
930 // otherwise SetClientSize() could have no effect if there already are
931 // size hints in effect that forbid requested client size.
933 const wxSize clientSize
= ComputeFittingClientSize(window
);
935 window
->SetMinClientSize(clientSize
);
936 window
->SetClientSize(clientSize
);
939 #if WXWIN_COMPATIBILITY_2_8
940 void wxSizer::SetVirtualSizeHints( wxWindow
*window
)
944 #endif // WXWIN_COMPATIBILITY_2_8
946 // TODO on mac we need a function that determines how much free space this
947 // min size contains, in order to make sure that we have 20 pixels of free
948 // space around the controls
949 wxSize
wxSizer::GetMaxClientSize( wxWindow
*window
) const
951 return window
->WindowToClientSize(window
->GetMaxSize());
954 wxSize
wxSizer::GetMinClientSize( wxWindow
*WXUNUSED(window
) )
956 return GetMinSize(); // Already returns client size.
959 wxSize
wxSizer::VirtualFitSize( wxWindow
*window
)
961 wxSize size
= GetMinClientSize( window
);
962 wxSize sizeMax
= GetMaxClientSize( window
);
964 // Limit the size if sizeMax != wxDefaultSize
966 if ( size
.x
> sizeMax
.x
&& sizeMax
.x
!= wxDefaultCoord
)
968 if ( size
.y
> sizeMax
.y
&& sizeMax
.y
!= wxDefaultCoord
)
974 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
983 wxSize
wxSizer::GetMinSize()
985 wxSize
ret( CalcMin() );
986 if (ret
.x
< m_minSize
.x
) ret
.x
= m_minSize
.x
;
987 if (ret
.y
< m_minSize
.y
) ret
.y
= m_minSize
.y
;
991 void wxSizer::DoSetMinSize( int width
, int height
)
994 m_minSize
.y
= height
;
997 bool wxSizer::DoSetItemMinSize( wxWindow
*window
, int width
, int height
)
999 wxASSERT_MSG( window
, _T("SetMinSize for NULL window") );
1001 // Is it our immediate child?
1003 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1006 wxSizerItem
*item
= node
->GetData();
1008 if (item
->GetWindow() == window
)
1010 item
->SetMinSize( width
, height
);
1013 node
= node
->GetNext();
1016 // No? Search any subsizers we own then
1018 node
= m_children
.GetFirst();
1021 wxSizerItem
*item
= node
->GetData();
1023 if ( item
->GetSizer() &&
1024 item
->GetSizer()->DoSetItemMinSize( window
, width
, height
) )
1026 // A child sizer found the requested windw, exit.
1029 node
= node
->GetNext();
1035 bool wxSizer::DoSetItemMinSize( wxSizer
*sizer
, int width
, int height
)
1037 wxASSERT_MSG( sizer
, _T("SetMinSize for NULL sizer") );
1039 // Is it our immediate child?
1041 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1044 wxSizerItem
*item
= node
->GetData();
1046 if (item
->GetSizer() == sizer
)
1048 item
->GetSizer()->DoSetMinSize( width
, height
);
1051 node
= node
->GetNext();
1054 // No? Search any subsizers we own then
1056 node
= m_children
.GetFirst();
1059 wxSizerItem
*item
= node
->GetData();
1061 if ( item
->GetSizer() &&
1062 item
->GetSizer()->DoSetItemMinSize( sizer
, width
, height
) )
1064 // A child found the requested sizer, exit.
1067 node
= node
->GetNext();
1073 bool wxSizer::DoSetItemMinSize( size_t index
, int width
, int height
)
1075 wxSizerItemList::compatibility_iterator node
= m_children
.Item( index
);
1077 wxCHECK_MSG( node
, false, _T("Failed to find child node") );
1079 wxSizerItem
*item
= node
->GetData();
1081 if (item
->GetSizer())
1083 // Sizers contains the minimal size in them, if not calculated ...
1084 item
->GetSizer()->DoSetMinSize( width
, height
);
1088 // ... but the minimal size of spacers and windows is stored via the item
1089 item
->SetMinSize( width
, height
);
1095 wxSizerItem
* wxSizer::GetItem( wxWindow
*window
, bool recursive
)
1097 wxASSERT_MSG( window
, _T("GetItem for NULL window") );
1099 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1102 wxSizerItem
*item
= node
->GetData();
1104 if (item
->GetWindow() == window
)
1108 else if (recursive
&& item
->IsSizer())
1110 wxSizerItem
*subitem
= item
->GetSizer()->GetItem( window
, true );
1115 node
= node
->GetNext();
1121 wxSizerItem
* wxSizer::GetItem( wxSizer
*sizer
, bool recursive
)
1123 wxASSERT_MSG( sizer
, _T("GetItem for NULL sizer") );
1125 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1128 wxSizerItem
*item
= node
->GetData();
1130 if (item
->GetSizer() == sizer
)
1134 else if (recursive
&& item
->IsSizer())
1136 wxSizerItem
*subitem
= item
->GetSizer()->GetItem( sizer
, true );
1141 node
= node
->GetNext();
1147 wxSizerItem
* wxSizer::GetItem( size_t index
)
1149 wxCHECK_MSG( index
< m_children
.GetCount(),
1151 _T("GetItem index is out of range") );
1153 return m_children
.Item( index
)->GetData();
1156 wxSizerItem
* wxSizer::GetItemById( int id
, bool recursive
)
1158 // This gets a sizer item by the id of the sizer item
1159 // and NOT the id of a window if the item is a window.
1161 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1164 wxSizerItem
*item
= node
->GetData();
1166 if (item
->GetId() == id
)
1170 else if (recursive
&& item
->IsSizer())
1172 wxSizerItem
*subitem
= item
->GetSizer()->GetItemById( id
, true );
1177 node
= node
->GetNext();
1183 bool wxSizer::Show( wxWindow
*window
, bool show
, bool recursive
)
1185 wxSizerItem
*item
= GetItem( window
, recursive
);
1196 bool wxSizer::Show( wxSizer
*sizer
, bool show
, bool recursive
)
1198 wxSizerItem
*item
= GetItem( sizer
, recursive
);
1209 bool wxSizer::Show( size_t index
, bool show
)
1211 wxSizerItem
*item
= GetItem( index
);
1222 void wxSizer::ShowItems( bool show
)
1224 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1227 node
->GetData()->Show( show
);
1228 node
= node
->GetNext();
1232 bool wxSizer::IsShown( wxWindow
*window
) const
1234 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1237 wxSizerItem
*item
= node
->GetData();
1239 if (item
->GetWindow() == window
)
1241 return item
->IsShown();
1243 node
= node
->GetNext();
1246 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1251 bool wxSizer::IsShown( wxSizer
*sizer
) const
1253 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1256 wxSizerItem
*item
= node
->GetData();
1258 if (item
->GetSizer() == sizer
)
1260 return item
->IsShown();
1262 node
= node
->GetNext();
1265 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1270 bool wxSizer::IsShown( size_t index
) const
1272 wxCHECK_MSG( index
< m_children
.GetCount(),
1274 _T("IsShown index is out of range") );
1276 return m_children
.Item( index
)->GetData()->IsShown();
1280 //---------------------------------------------------------------------------
1282 //---------------------------------------------------------------------------
1284 wxGridSizer::wxGridSizer( int rows
, int cols
, int vgap
, int hgap
)
1285 : m_rows( ( cols
== 0 && rows
== 0 ) ? 1 : rows
)
1292 wxGridSizer::wxGridSizer( int cols
, int vgap
, int hgap
)
1293 : m_rows( cols
== 0 ? 1 : 0 )
1300 int wxGridSizer::CalcRowsCols(int& nrows
, int& ncols
) const
1302 int nitems
= m_children
.GetCount();
1308 nrows
= (nitems
+ m_cols
- 1) / m_cols
;
1312 ncols
= (nitems
+ m_rows
- 1) / m_rows
;
1315 else // 0 columns, 0 rows?
1317 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
1326 void wxGridSizer::RecalcSizes()
1328 int nitems
, nrows
, ncols
;
1329 if ( (nitems
= CalcRowsCols(nrows
, ncols
)) == 0 )
1332 wxSize
sz( GetSize() );
1333 wxPoint
pt( GetPosition() );
1335 int w
= (sz
.x
- (ncols
- 1) * m_hgap
) / ncols
;
1336 int h
= (sz
.y
- (nrows
- 1) * m_vgap
) / nrows
;
1339 for (int c
= 0; c
< ncols
; c
++)
1342 for (int r
= 0; r
< nrows
; r
++)
1344 int i
= r
* ncols
+ c
;
1347 wxSizerItemList::compatibility_iterator node
= m_children
.Item( i
);
1349 wxASSERT_MSG( node
, _T("Failed to find SizerItemList node") );
1351 SetItemBounds( node
->GetData(), x
, y
, w
, h
);
1359 wxSize
wxGridSizer::CalcMin()
1362 if ( CalcRowsCols(nrows
, ncols
) == 0 )
1365 // Find the max width and height for any component
1369 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
1372 wxSizerItem
*item
= node
->GetData();
1373 wxSize
sz( item
->CalcMin() );
1375 w
= wxMax( w
, sz
.x
);
1376 h
= wxMax( h
, sz
.y
);
1378 node
= node
->GetNext();
1381 // In case we have a nested sizer with a two step algo , give it
1382 // a chance to adjust to that (we give it width component)
1383 node
= m_children
.GetFirst();
1384 bool didChangeMinSize
= false;
1387 wxSizerItem
*item
= node
->GetData();
1388 didChangeMinSize
|= item
->InformFirstDirection( wxHORIZONTAL
, w
, -1 );
1390 node
= node
->GetNext();
1393 // And redo iteration in case min size changed
1394 if( didChangeMinSize
)
1396 node
= m_children
.GetFirst();
1400 wxSizerItem
*item
= node
->GetData();
1401 wxSize
sz( item
->GetMinSizeWithBorder() );
1403 w
= wxMax( w
, sz
.x
);
1404 h
= wxMax( h
, sz
.y
);
1406 node
= node
->GetNext();
1410 return wxSize( ncols
* w
+ (ncols
-1) * m_hgap
,
1411 nrows
* h
+ (nrows
-1) * m_vgap
);
1414 void wxGridSizer::SetItemBounds( wxSizerItem
*item
, int x
, int y
, int w
, int h
)
1417 wxSize
sz( item
->GetMinSizeWithBorder() );
1418 int flag
= item
->GetFlag();
1420 if ((flag
& wxEXPAND
) || (flag
& wxSHAPED
))
1426 if (flag
& wxALIGN_CENTER_HORIZONTAL
)
1428 pt
.x
= x
+ (w
- sz
.x
) / 2;
1430 else if (flag
& wxALIGN_RIGHT
)
1432 pt
.x
= x
+ (w
- sz
.x
);
1435 if (flag
& wxALIGN_CENTER_VERTICAL
)
1437 pt
.y
= y
+ (h
- sz
.y
) / 2;
1439 else if (flag
& wxALIGN_BOTTOM
)
1441 pt
.y
= y
+ (h
- sz
.y
);
1445 item
->SetDimension(pt
, sz
);
1448 //---------------------------------------------------------------------------
1450 //---------------------------------------------------------------------------
1452 wxFlexGridSizer::wxFlexGridSizer( int rows
, int cols
, int vgap
, int hgap
)
1453 : wxGridSizer( rows
, cols
, vgap
, hgap
),
1454 m_flexDirection(wxBOTH
),
1455 m_growMode(wxFLEX_GROWMODE_SPECIFIED
)
1459 wxFlexGridSizer::wxFlexGridSizer( int cols
, int vgap
, int hgap
)
1460 : wxGridSizer( cols
, vgap
, hgap
),
1461 m_flexDirection(wxBOTH
),
1462 m_growMode(wxFLEX_GROWMODE_SPECIFIED
)
1466 wxFlexGridSizer::~wxFlexGridSizer()
1470 void wxFlexGridSizer::RecalcSizes()
1473 if ( !CalcRowsCols(nrows
, ncols
) )
1476 const wxPoint
pt(GetPosition());
1477 const wxSize
sz(GetSize());
1479 AdjustForGrowables(sz
);
1481 wxSizerItemList::const_iterator i
= m_children
.begin();
1482 const wxSizerItemList::const_iterator end
= m_children
.end();
1485 for ( int r
= 0; r
< nrows
; r
++ )
1487 if ( m_rowHeights
[r
] == -1 )
1489 // this row is entirely hidden, skip it
1490 for ( int c
= 0; c
< ncols
; c
++ )
1501 const int hrow
= m_rowHeights
[r
];
1502 int h
= sz
.y
- y
; // max remaining height, don't overflow it
1507 for ( int c
= 0; c
< ncols
&& i
!= end
; c
++, ++i
)
1509 const int wcol
= m_colWidths
[c
];
1514 int w
= sz
.x
- x
; // max possible value, ensure we don't overflow
1518 SetItemBounds(*i
, pt
.x
+ x
, pt
.y
+ y
, w
, h
);
1530 // helper function used in CalcMin() to sum up the sizes of non-hidden items
1531 static int SumArraySizes(const wxArrayInt
& sizes
, int gap
)
1533 // Sum total minimum size, including gaps between rows/columns.
1534 // -1 is used as a magic number meaning empty row/column.
1537 const size_t count
= sizes
.size();
1538 for ( size_t n
= 0; n
< count
; n
++ )
1540 if ( sizes
[n
] != -1 )
1543 total
+= gap
; // separate from the previous column
1552 void wxFlexGridSizer::FindWidthsAndHeights(int nrows
, int ncols
)
1554 // We have to recalculate the sizes in case the item minimum size has
1555 // changed since the previous layout, or the item has been hidden using
1556 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1557 // dimension of the row/column will be -1, indicating that the column
1558 // itself is hidden.
1559 m_rowHeights
.assign(nrows
, -1);
1560 m_colWidths
.assign(ncols
, -1);
1562 // n is the index of the item in left-to-right top-to-bottom order
1564 for ( wxSizerItemList::iterator i
= m_children
.begin();
1565 i
!= m_children
.end();
1568 wxSizerItem
* const item
= *i
;
1569 if ( item
->IsShown() )
1571 // NOTE: Not doing the calculation here, this is just
1572 // for finding max values.
1573 const wxSize
sz(item
->GetMinSizeWithBorder());
1575 const int row
= n
/ ncols
;
1576 const int col
= n
% ncols
;
1578 if ( sz
.y
> m_rowHeights
[row
] )
1579 m_rowHeights
[row
] = sz
.y
;
1580 if ( sz
.x
> m_colWidths
[col
] )
1581 m_colWidths
[col
] = sz
.x
;
1585 AdjustForFlexDirection();
1587 m_calculatedMinSize
= wxSize(SumArraySizes(m_colWidths
, m_hgap
),
1588 SumArraySizes(m_rowHeights
, m_vgap
));
1591 wxSize
wxFlexGridSizer::CalcMin()
1596 // Number of rows/columns can change as items are added or removed.
1597 if ( !CalcRowsCols(nrows
, ncols
) )
1601 // We have to recalculate the sizes in case the item minimum size has
1602 // changed since the previous layout, or the item has been hidden using
1603 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1604 // dimension of the row/column will be -1, indicating that the column
1605 // itself is hidden.
1606 m_rowHeights
.assign(nrows
, -1);
1607 m_colWidths
.assign(ncols
, -1);
1609 // n is the index of the item in left-to-right top-to-bottom order
1611 for ( wxSizerItemList::iterator i
= m_children
.begin();
1612 i
!= m_children
.end();
1615 wxSizerItem
* const item
= *i
;
1616 if ( item
->IsShown() )
1622 // The stage of looking for max values in each row/column has been
1623 // made a separate function, since it's reused in AdjustForGrowables.
1624 FindWidthsAndHeights(nrows
,ncols
);
1626 return m_calculatedMinSize
;
1629 void wxFlexGridSizer::AdjustForFlexDirection()
1631 // the logic in CalcMin works when we resize flexibly in both directions
1632 // but maybe this is not the case
1633 if ( m_flexDirection
!= wxBOTH
)
1635 // select the array corresponding to the direction in which we do *not*
1637 wxArrayInt
& array
= m_flexDirection
== wxVERTICAL
? m_colWidths
1640 const size_t count
= array
.GetCount();
1642 // find the largest value in this array
1646 for ( n
= 0; n
< count
; ++n
)
1648 if ( array
[n
] > largest
)
1652 // and now fill it with the largest value
1653 for ( n
= 0; n
< count
; ++n
)
1655 // don't touch hidden rows
1656 if ( array
[n
] != -1 )
1662 // helper of AdjustForGrowables() which is called for rows/columns separately
1665 // delta: the extra space, we do nothing unless it's positive
1666 // growable: indices or growable rows/cols in sizes array
1667 // sizes: the height/widths of rows/cols to adjust
1668 // proportions: proportions of the growable rows/cols or NULL if they all
1669 // should be assumed to have proportion of 1
1671 DoAdjustForGrowables(int delta
,
1672 const wxArrayInt
& growable
,
1674 const wxArrayInt
*proportions
)
1679 // total sum of proportions of all non-hidden rows
1680 int sum_proportions
= 0;
1682 // number of currently shown growable rows
1685 const int max_idx
= sizes
.size();
1687 const size_t count
= growable
.size();
1689 for ( idx
= 0; idx
< count
; idx
++ )
1691 // Since the number of rows/columns can change as items are
1692 // inserted/deleted, we need to verify at runtime that the
1693 // requested growable rows/columns are still valid.
1694 if ( growable
[idx
] >= max_idx
)
1697 // If all items in a row/column are hidden, that row/column will
1698 // have a dimension of -1. This causes the row/column to be
1699 // hidden completely.
1700 if ( sizes
[growable
[idx
]] == -1 )
1704 sum_proportions
+= (*proportions
)[idx
];
1712 // the remaining extra free space, adjusted during each iteration
1713 for ( idx
= 0; idx
< count
; idx
++ )
1715 if ( growable
[idx
] >= max_idx
)
1718 if ( sizes
[ growable
[idx
] ] == -1 )
1722 if ( sum_proportions
== 0 )
1724 // no growable rows -- divide extra space evenly among all
1725 cur_delta
= delta
/num
;
1728 else // allocate extra space proportionally
1730 const int cur_prop
= (*proportions
)[idx
];
1731 cur_delta
= (delta
*cur_prop
)/sum_proportions
;
1732 sum_proportions
-= cur_prop
;
1735 sizes
[growable
[idx
]] += cur_delta
;
1740 void wxFlexGridSizer::AdjustForGrowables(const wxSize
& sz
)
1742 if ( (m_flexDirection
& wxHORIZONTAL
) || (m_growMode
!= wxFLEX_GROWMODE_NONE
) )
1744 DoAdjustForGrowables
1746 sz
.x
- m_calculatedMinSize
.x
,
1749 m_growMode
== wxFLEX_GROWMODE_SPECIFIED
? &m_growableColsProportions
1753 // This gives nested objects that benefit from knowing one size
1754 // component in advance the chance to use that.
1755 bool didAdjustMinSize
= false;
1757 CalcRowsCols(nrows
, ncols
);
1759 // Iterate over all items and inform about column width
1761 for ( wxSizerItemList::iterator i
= m_children
.begin();
1762 i
!= m_children
.end();
1765 const int col
= n
% ncols
;
1766 didAdjustMinSize
|= (*i
)->InformFirstDirection(wxHORIZONTAL
, m_colWidths
[col
], sz
.y
- m_calculatedMinSize
.y
);
1769 // Only redo if info was actually used
1770 if( didAdjustMinSize
)
1772 DoAdjustForGrowables
1774 sz
.x
- m_calculatedMinSize
.x
,
1777 m_growMode
== wxFLEX_GROWMODE_SPECIFIED
? &m_growableColsProportions
1783 if ( (m_flexDirection
& wxVERTICAL
) || (m_growMode
!= wxFLEX_GROWMODE_NONE
) )
1785 // pass NULL instead of proportions if the grow mode is ALL as we
1786 // should treat all rows as having proportion of 1 then
1787 DoAdjustForGrowables
1789 sz
.y
- m_calculatedMinSize
.y
,
1792 m_growMode
== wxFLEX_GROWMODE_SPECIFIED
? &m_growableRowsProportions
1799 void wxFlexGridSizer::AddGrowableRow( size_t idx
, int proportion
)
1801 m_growableRows
.Add( idx
);
1802 m_growableRowsProportions
.Add( proportion
);
1805 void wxFlexGridSizer::AddGrowableCol( size_t idx
, int proportion
)
1807 m_growableCols
.Add( idx
);
1808 m_growableColsProportions
.Add( proportion
);
1811 // helper function for RemoveGrowableCol/Row()
1813 DoRemoveFromArrays(size_t idx
, wxArrayInt
& items
, wxArrayInt
& proportions
)
1815 const size_t count
= items
.size();
1816 for ( size_t n
= 0; n
< count
; n
++ )
1818 if ( (size_t)items
[n
] == idx
)
1821 proportions
.RemoveAt(n
);
1826 wxFAIL_MSG( _T("column/row is already not growable") );
1829 void wxFlexGridSizer::RemoveGrowableCol( size_t idx
)
1831 DoRemoveFromArrays(idx
, m_growableCols
, m_growableColsProportions
);
1834 void wxFlexGridSizer::RemoveGrowableRow( size_t idx
)
1836 DoRemoveFromArrays(idx
, m_growableRows
, m_growableRowsProportions
);
1839 //---------------------------------------------------------------------------
1841 //---------------------------------------------------------------------------
1843 void wxBoxSizer::RecalcSizes()
1845 if ( m_children
.empty() )
1848 const wxCoord totalMinorSize
= GetSizeInMinorDir(m_size
);
1850 // the amount of free space which we should redistribute among the
1851 // stretchable items (i.e. those with non zero proportion)
1852 int delta
= GetSizeInMajorDir(m_size
) - GetSizeInMajorDir(m_minSize
);
1855 // Inform child items about the size in minor direction, that can
1856 // change how much free space we have in major dir and how to distribute it.
1857 int majorMinSum
= 0;
1858 wxSizerItemList::const_iterator i
;
1859 for ( i
= m_children
.begin();
1860 i
!= m_children
.end();
1863 wxSizerItem
* const item
= *i
;
1865 if ( !item
->IsShown() )
1868 wxSize szMinPrev
= item
->GetMinSizeWithBorder();
1869 item
->InformFirstDirection(m_orient
^wxBOTH
,totalMinorSize
,delta
);
1870 wxSize szMin
= item
->GetMinSizeWithBorder();
1871 int deltaChange
= GetSizeInMajorDir(szMin
-szMinPrev
);
1874 // Since we passed available space along to the item, it should not
1875 // take too much, so delta should not become negative.
1876 delta
-= deltaChange
;
1878 majorMinSum
+= GetSizeInMajorDir(item
->GetMinSizeWithBorder());
1880 // And update our min size
1881 SizeInMajorDir(m_minSize
) = majorMinSum
;
1884 // might have a new delta now
1885 delta
= GetSizeInMajorDir(m_size
) - GetSizeInMajorDir(m_minSize
);
1887 // the position at which we put the next child
1888 wxPoint
pt(m_position
);
1890 int totalProportion
= m_totalProportion
;
1891 for ( i
= m_children
.begin();
1892 i
!= m_children
.end();
1895 wxSizerItem
* const item
= *i
;
1897 if ( !item
->IsShown() )
1900 const wxSize
sizeThis(item
->GetMinSizeWithBorder());
1902 // adjust the size in the major direction using the proportion
1903 wxCoord majorSize
= GetSizeInMajorDir(sizeThis
);
1904 const int propItem
= item
->GetProportion();
1907 const int deltaItem
= (delta
* propItem
) / totalProportion
;
1909 majorSize
+= deltaItem
;
1912 totalProportion
-= propItem
;
1916 // apply the alignment in the minor direction
1917 wxPoint
posChild(pt
);
1919 wxCoord minorSize
= GetSizeInMinorDir(sizeThis
);
1920 const int flag
= item
->GetFlag();
1921 if ( flag
& (wxEXPAND
| wxSHAPED
) )
1923 minorSize
= totalMinorSize
;
1925 else if ( flag
& (IsVertical() ? wxALIGN_RIGHT
: wxALIGN_BOTTOM
) )
1927 PosInMinorDir(posChild
) += totalMinorSize
- minorSize
;
1929 // NB: wxCENTRE is used here only for backwards compatibility,
1930 // wxALIGN_CENTRE should be used in new code
1931 else if ( flag
& (wxCENTER
| wxALIGN_CENTRE
) )
1933 PosInMinorDir(posChild
) += (totalMinorSize
- minorSize
) / 2;
1937 // apply RTL adjustment for horizontal sizers:
1938 if ( !IsVertical() && m_containingWindow
)
1940 posChild
.x
= m_containingWindow
->AdjustForLayoutDirection
1948 // finally set size of this child and advance to the next one
1949 item
->SetDimension(posChild
, SizeFromMajorMinor(majorSize
, minorSize
));
1951 PosInMajorDir(pt
) += majorSize
;
1955 wxSize
wxBoxSizer::CalcMin()
1957 m_totalProportion
= 0;
1958 m_minSize
= wxSize(0, 0);
1960 // calculate the minimal sizes for all items and count sum of proportions
1961 for ( wxSizerItemList::const_iterator i
= m_children
.begin();
1962 i
!= m_children
.end();
1965 wxSizerItem
* const item
= *i
;
1967 if ( !item
->IsShown() )
1970 const wxSize sizeMinThis
= item
->CalcMin();
1971 SizeInMajorDir(m_minSize
) += GetSizeInMajorDir(sizeMinThis
);
1972 if ( GetSizeInMinorDir(sizeMinThis
) > GetSizeInMinorDir(m_minSize
) )
1973 SizeInMinorDir(m_minSize
) = GetSizeInMinorDir(sizeMinThis
);
1975 m_totalProportion
+= item
->GetProportion();
1981 //---------------------------------------------------------------------------
1983 //---------------------------------------------------------------------------
1985 #define wxDEFAULT_PROPORTION_LAST 1000000
1987 // User data to hold old proportion for last item on line
1988 // (which might be extended)
1989 struct wxPropHolder
: public wxObject
1991 wxPropHolder( ) : m_item(0), m_propOld(0) { }
1992 void Init( wxSizerItem
*item
, int propOld
) { m_item
=item
; m_propOld
=propOld
; }
1994 wxSizerItem
*m_item
;
1998 IMPLEMENT_DYNAMIC_CLASS(wxWrapSizer
, wxBoxSizer
);
2000 wxWrapSizer::wxWrapSizer( int orient
, int flags
)
2001 : wxBoxSizer(orient
),
2002 m_prim_size_last( -1 ),
2003 m_rows(orient
^wxBOTH
),
2008 wxWrapSizer::~wxWrapSizer()
2010 // Have to clear grand child items so that they're not deleted twice
2011 for( int ix
=m_rows
.GetChildren().GetCount()-1; ix
>=0; ix
-- )
2013 wxSizer
*psz
= m_rows
.GetItem((size_t)ix
)->GetSizer();
2014 wxSizerItemList
&sl
= psz
->GetChildren();
2015 while( sl
.GetLast() )
2016 sl
.Erase( sl
.GetLast() );
2021 bool wxWrapSizer::InformFirstDirection( int direction
, int size
, int WXUNUSED(availableOtherDir
) )
2025 // Better to keep value, then CalcMin will work better
2026 //m_prim_size_last = -1;
2029 if( direction
==m_orient
)
2031 // The direction is same as our primary, so we can make use of it
2032 m_prim_size_last
= size
;
2040 void wxWrapSizer::AdjustPropLastItem(wxSizer
*psz
, wxSizerItem
*itemLast
)
2042 wxSizerItem
*psi
= m_rows
.GetItem(psz
);
2044 wxPropHolder
*pph
= (wxPropHolder
*)psi
->GetUserData();
2046 psi
->SetUserData( pph
=new wxPropHolder
);
2048 pph
->Init( itemLast
, itemLast
->GetProportion() );
2049 itemLast
->SetProportion( wxDEFAULT_PROPORTION_LAST
);
2052 void wxWrapSizer::RecalcSizes()
2054 wxASSERT( m_orient
&wxBOTH
);
2055 if (m_children
.GetCount() == 0)
2058 // What we do here is to put our items into child box sizers,
2059 // as many of them as we have lines.
2061 // Empty all items in all rows in owned sizer.
2062 // We have to access the list directly, since we don't want to
2063 // destroy the wxSizerItems.
2064 for( int ix
=m_rows
.GetChildren().GetCount()-1; ix
>=0; ix
-- ){
2065 wxSizerItem
*psi
= m_rows
.GetItem( (size_t)ix
);
2067 // Restore proportion for last item on line (if item has not been deleted)
2068 wxPropHolder
*pph
= (wxPropHolder
*)psi
->GetUserData();
2069 if( pph
&& GetChildren().Find(pph
->m_item
) )
2070 pph
->m_item
->SetProportion(pph
->m_propOld
);
2072 wxSizer
*psz
= psi
->GetSizer();
2074 wxSizerItemList
&sl
= psz
->GetChildren();
2075 while( sl
.GetLast() )
2076 sl
.Erase( sl
.GetLast() );
2079 int lineSumMajor
= 0;
2080 int majorSize
= GetSizeInMajorDir(m_size
);
2082 // Make sure we have at least one child sizer
2084 if( !m_rows
.GetChildren().GetCount() )
2085 m_rows
.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND
);
2087 // The sizer where to insert items in
2088 wxSizer
*psz
= m_rows
.GetItem((size_t)0)->GetSizer();
2091 // Now put our child items into child sizers instead
2092 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
2093 wxSizerItem
*item
= NULL
, *itemLast
=NULL
;
2096 item
= node
->GetData();
2097 if ( item
->IsShown() )
2099 wxSize minSz
= item
->GetMinSize();
2100 int minSzMajor
= GetSizeInMajorDir(minSz
);
2102 // More space on this line?
2103 if( !lineSumMajor
|| lineSumMajor
+minSzMajor
<=majorSize
)
2105 lineSumMajor
+= minSzMajor
;
2109 lineSumMajor
= minSzMajor
;
2110 // Get a new empty sizer to insert into
2111 if( (int)m_rows
.GetChildren().GetCount()<=m_n_line
)
2112 m_rows
.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND
);
2114 // If we have extend-last-on-each-line mode, then do so now
2115 // Note: We must store old proportion value then.
2116 if( m_flags
&wxEXTEND_LAST_ON_EACH_LINE
)
2117 AdjustPropLastItem(psz
,itemLast
);
2119 // The sizer where to insert items in
2120 psz
= m_rows
.GetItem(m_n_line
++)->GetSizer();
2124 // If item is a window, it now has a pointer to the child sizer,
2125 // which is wrong. Set it to point to us.
2126 if( item
->GetWindow() )
2127 item
->GetWindow()->SetContainingSizer( this );
2129 node
= node
->GetNext();
2132 // If we have extend-last-on-each-line mode, then do so now
2133 if( m_flags
&wxEXTEND_LAST_ON_EACH_LINE
)
2134 AdjustPropLastItem(psz
,itemLast
);
2136 // If we have more sizers than lines, remove them
2137 while( (int)m_rows
.GetChildren().GetCount()>m_n_line
)
2138 m_rows
.Remove( m_n_line
);
2140 // Now do layout on row sizer
2141 m_rows
.SetDimension( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
2143 // Remember this to next time (will be overridden by InformFirstDirection if used)
2144 m_prim_size_last
= GetSizeInMajorDir(m_size
);
2148 wxSize
wxWrapSizer::CalcMin()
2150 if (m_children
.GetCount() == 0)
2153 // Algorithm for calculating min size: (assuming horizontal orientation)
2154 // X: Max width of all members
2155 // Y: Based on last X, calculate how many lines needed
2156 // First time around, assume all items fits on one line
2160 int lineMaxMinor
= 0;
2161 int lineSumMajor
= 0;
2164 // precalc item minsizes and fit on lines (preliminary)
2165 wxSizerItemList::compatibility_iterator node
= m_children
.GetFirst();
2168 wxSizerItem
*item
= node
->GetData();
2169 if ( item
->IsShown() )
2171 wxSize minSz
= item
->CalcMin();
2172 int szMajor
= GetSizeInMajorDir(minSz
);
2173 int szMinor
= GetSizeInMinorDir(minSz
);
2174 if( szMajor
>maxMajor
) maxMajor
= szMajor
;
2175 // More space on this line?
2176 if( m_prim_size_last
<0 || !lineSumMajor
||
2177 lineSumMajor
+szMajor
<=m_prim_size_last
)
2179 lineSumMajor
+= szMajor
;
2180 if( szMinor
>lineMaxMinor
)
2181 lineMaxMinor
= szMinor
;
2185 minorSum
+= lineMaxMinor
; // Add height of highest item on last line
2187 lineMaxMinor
= szMinor
;
2188 lineSumMajor
= szMajor
;
2191 node
= node
->GetNext();
2193 minorSum
+= lineMaxMinor
; // Add height of highest item on last line
2195 m_minSize
= SizeFromMajorMinor(maxMajor
, minorSum
);
2199 //---------------------------------------------------------------------------
2201 //---------------------------------------------------------------------------
2205 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
2206 : wxBoxSizer( orient
),
2209 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
2211 // do this so that our Detach() is called if the static box is destroyed
2213 m_staticBox
->SetContainingSizer(this);
2216 wxStaticBoxSizer::wxStaticBoxSizer(int orient
, wxWindow
*win
, const wxString
& s
)
2217 : wxBoxSizer(orient
),
2218 m_staticBox(new wxStaticBox(win
, wxID_ANY
, s
))
2221 m_staticBox
->SetContainingSizer(this);
2224 wxStaticBoxSizer::~wxStaticBoxSizer()
2229 static void GetStaticBoxBorders( wxStaticBox
*box
,
2233 // this has to be done platform by platform as there is no way to
2234 // guess the thickness of a wxStaticBox border
2235 box
->GetBordersForSizer(borderTop
, borderOther
);
2238 void wxStaticBoxSizer::RecalcSizes()
2240 int top_border
, other_border
;
2241 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
2243 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
2245 wxPoint
old_pos( m_position
);
2246 m_position
.x
+= other_border
;
2247 m_position
.y
+= top_border
;
2248 wxSize
old_size( m_size
);
2249 m_size
.x
-= 2*other_border
;
2250 m_size
.y
-= top_border
+ other_border
;
2252 wxBoxSizer::RecalcSizes();
2254 m_position
= old_pos
;
2258 wxSize
wxStaticBoxSizer::CalcMin()
2260 int top_border
, other_border
;
2261 GetStaticBoxBorders(m_staticBox
, &top_border
, &other_border
);
2263 wxSize
ret( wxBoxSizer::CalcMin() );
2264 ret
.x
+= 2*other_border
;
2265 ret
.y
+= other_border
+ top_border
;
2270 void wxStaticBoxSizer::ShowItems( bool show
)
2272 m_staticBox
->Show( show
);
2273 wxBoxSizer::ShowItems( show
);
2276 bool wxStaticBoxSizer::Detach( wxWindow
*window
)
2278 // avoid deleting m_staticBox in our dtor if it's being detached from the
2279 // sizer (which can happen because it's being already destroyed for
2281 if ( window
== m_staticBox
)
2287 return wxSizer::Detach( window
);
2290 #endif // wxUSE_STATBOX
2294 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
2295 : wxBoxSizer(wxHORIZONTAL
)
2297 // Vertical buttons with lots of space on either side
2298 // looks rubbish on WinCE, so let's not do this for now.
2299 // If we are going to use vertical buttons, we should
2300 // put the sizer to the right of other controls in the dialog,
2301 // and that's beyond the scope of this sizer.
2303 bool is_pda
= (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA
);
2304 // If we have a PDA screen, put yes/no button over
2305 // all other buttons, otherwise on the left side.
2307 m_orient
= wxVERTICAL
;
2310 m_buttonAffirmative
= NULL
;
2311 m_buttonApply
= NULL
;
2312 m_buttonNegative
= NULL
;
2313 m_buttonCancel
= NULL
;
2314 m_buttonHelp
= NULL
;
2317 void wxStdDialogButtonSizer::AddButton(wxButton
*mybutton
)
2319 switch (mybutton
->GetId())
2324 m_buttonAffirmative
= mybutton
;
2327 m_buttonApply
= mybutton
;
2330 m_buttonNegative
= mybutton
;
2334 m_buttonCancel
= mybutton
;
2337 case wxID_CONTEXT_HELP
:
2338 m_buttonHelp
= mybutton
;
2345 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton
*button
)
2347 m_buttonAffirmative
= button
;
2350 void wxStdDialogButtonSizer::SetNegativeButton( wxButton
*button
)
2352 m_buttonNegative
= button
;
2355 void wxStdDialogButtonSizer::SetCancelButton( wxButton
*button
)
2357 m_buttonCancel
= button
;
2360 void wxStdDialogButtonSizer::Realize()
2363 Add(0, 0, 0, wxLEFT
, 6);
2365 Add((wxWindow
*)m_buttonHelp
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 6);
2367 if (m_buttonNegative
){
2368 // HIG POLICE BULLETIN - destructive buttons need extra padding
2369 // 24 pixels on either side
2370 Add((wxWindow
*)m_buttonNegative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 12);
2373 // extra whitespace between help/negative and cancel/ok buttons
2374 Add(0, 0, 1, wxEXPAND
, 0);
2376 if (m_buttonCancel
){
2377 Add((wxWindow
*)m_buttonCancel
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 6);
2378 // Cancel or help should be default
2379 // m_buttonCancel->SetDefaultButton();
2382 // Ugh, Mac doesn't really have apply dialogs, so I'll just
2383 // figure the best place is between Cancel and OK
2385 Add((wxWindow
*)m_buttonApply
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 6);
2387 if (m_buttonAffirmative
){
2388 Add((wxWindow
*)m_buttonAffirmative
, 0, wxALIGN_CENTRE
| wxLEFT
, 6);
2390 if (m_buttonAffirmative
->GetId() == wxID_SAVE
){
2391 // these buttons have set labels under Mac so we should use them
2392 m_buttonAffirmative
->SetLabel(_("Save"));
2393 if (m_buttonNegative
)
2394 m_buttonNegative
->SetLabel(_("Don't Save"));
2398 // Extra space around and at the right
2400 #elif defined(__WXGTK20__)
2401 Add(0, 0, 0, wxLEFT
, 9);
2403 Add((wxWindow
*)m_buttonHelp
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 3);
2405 // extra whitespace between help and cancel/ok buttons
2406 Add(0, 0, 1, wxEXPAND
, 0);
2408 if (m_buttonNegative
){
2409 Add((wxWindow
*)m_buttonNegative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 3);
2412 // according to HIG, in explicit apply windows the order is:
2413 // [ Help Apply Cancel OK ]
2415 Add((wxWindow
*)m_buttonApply
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 3);
2417 if (m_buttonCancel
){
2418 Add((wxWindow
*)m_buttonCancel
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, 3);
2419 // Cancel or help should be default
2420 // m_buttonCancel->SetDefaultButton();
2423 if (m_buttonAffirmative
)
2424 Add((wxWindow
*)m_buttonAffirmative
, 0, wxALIGN_CENTRE
| wxLEFT
, 6);
2425 #elif defined(__WXMSW__)
2428 // right-justify buttons
2429 Add(0, 0, 1, wxEXPAND
, 0);
2431 if (m_buttonAffirmative
){
2432 Add((wxWindow
*)m_buttonAffirmative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonAffirmative
->ConvertDialogToPixels(wxSize(2, 0)).x
);
2435 if (m_buttonNegative
){
2436 Add((wxWindow
*)m_buttonNegative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonNegative
->ConvertDialogToPixels(wxSize(2, 0)).x
);
2439 if (m_buttonCancel
){
2440 Add((wxWindow
*)m_buttonCancel
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonCancel
->ConvertDialogToPixels(wxSize(2, 0)).x
);
2443 Add((wxWindow
*)m_buttonApply
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonApply
->ConvertDialogToPixels(wxSize(2, 0)).x
);
2446 Add((wxWindow
*)m_buttonHelp
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonHelp
->ConvertDialogToPixels(wxSize(2, 0)).x
);
2448 // GTK+1 and any other platform
2450 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
2452 Add((wxWindow
*)m_buttonHelp
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonHelp
->ConvertDialogToPixels(wxSize(4, 0)).x
);
2454 // extra whitespace between help and cancel/ok buttons
2455 Add(0, 0, 1, wxEXPAND
, 0);
2458 Add((wxWindow
*)m_buttonApply
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonApply
->ConvertDialogToPixels(wxSize(4, 0)).x
);
2460 if (m_buttonAffirmative
){
2461 Add((wxWindow
*)m_buttonAffirmative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonAffirmative
->ConvertDialogToPixels(wxSize(4, 0)).x
);
2464 if (m_buttonNegative
){
2465 Add((wxWindow
*)m_buttonNegative
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonNegative
->ConvertDialogToPixels(wxSize(4, 0)).x
);
2468 if (m_buttonCancel
){
2469 Add((wxWindow
*)m_buttonCancel
, 0, wxALIGN_CENTRE
| wxLEFT
| wxRIGHT
, m_buttonCancel
->ConvertDialogToPixels(wxSize(4, 0)).x
);
2470 // Cancel or help should be default
2471 // m_buttonCancel->SetDefaultButton();
2477 #endif // wxUSE_BUTTON