1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn
8 // Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "sizer.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
25 #include "wx/statbox.h"
27 //---------------------------------------------------------------------------
29 IMPLEMENT_ABSTRACT_CLASS(wxSizerItem
, wxObject
);
30 IMPLEMENT_ABSTRACT_CLASS(wxSizer
, wxObject
);
31 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer
, wxSizer
);
32 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer
, wxBoxSizer
);
34 //---------------------------------------------------------------------------
36 //---------------------------------------------------------------------------
38 wxSizerItem::wxSizerItem( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
40 m_window
= (wxWindow
*) NULL
;
41 m_sizer
= (wxSizer
*) NULL
;
45 m_userData
= userData
;
47 // minimal size is the initial size
51 SetRatio(width
, height
);
53 // size is set directly
57 wxSizerItem::wxSizerItem( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
60 m_sizer
= (wxSizer
*) NULL
;
64 m_userData
= userData
;
66 // minimal size is the initial size
67 m_minSize
= window
->GetSize();
69 // aspect ratio calculated from initial size
72 // size is calculated later
76 wxSizerItem::wxSizerItem( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
78 m_window
= (wxWindow
*) NULL
;
83 m_userData
= userData
;
85 // minimal size is calculated later
89 // size is calculated later
93 wxSizerItem::~wxSizerItem()
102 wxSize
wxSizerItem::GetSize()
106 ret
= m_sizer
->GetSize();
109 ret
= m_window
->GetSize();
116 if (m_flag
& wxNORTH
)
118 if (m_flag
& wxSOUTH
)
124 wxSize
wxSizerItem::CalcMin()
129 ret
= m_sizer
->CalcMin();
130 // if we have to preserve aspect ratio _AND_ this is
131 // the first-time calculation, consider ret to be initial size
132 if ((m_flag
& wxSHAPED
) && !m_ratio
) SetRatio(ret
);
136 The minimum size of a window should be the
137 initial size, as saved in m_minSize, not the
142 ret = m_window->GetSize();
144 else ret
= m_minSize
;
150 if (m_flag
& wxNORTH
)
152 if (m_flag
& wxSOUTH
)
158 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size
)
169 if (m_flag
& wxNORTH
)
174 if (m_flag
& wxSOUTH
)
178 if (m_flag
& wxSHAPED
) {
179 // adjust aspect ratio
180 int rwidth
= (int) (size
.y
* m_ratio
);
181 if (rwidth
> size
.x
) {
183 int rheight
= (int) (size
.x
/ m_ratio
);
184 // add vertical space
185 if (m_flag
& wxALIGN_CENTER_VERTICAL
)
186 pos
.y
+= (size
.y
- rheight
) / 2;
187 else if (m_flag
& wxALIGN_BOTTOM
)
188 pos
.y
+= (size
.y
- rheight
);
189 // use reduced dimensions
191 } else if (rwidth
< size
.x
) {
192 // add horizontal space
193 if (m_flag
& wxALIGN_CENTER_HORIZONTAL
)
194 pos
.x
+= (size
.x
- rwidth
) / 2;
195 else if (m_flag
& wxALIGN_RIGHT
)
196 pos
.x
+= (size
.x
- rwidth
);
202 m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y
);
205 m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
);
210 bool wxSizerItem::IsWindow()
212 return (m_window
!= NULL
);
215 bool wxSizerItem::IsSizer()
217 return (m_sizer
!= NULL
);
220 bool wxSizerItem::IsSpacer()
222 return (m_window
== NULL
) && (m_sizer
== NULL
);
225 //---------------------------------------------------------------------------
227 //---------------------------------------------------------------------------
231 m_children
.DeleteContents( TRUE
);
238 void wxSizer::Add( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
240 m_children
.Append( new wxSizerItem( window
, option
, flag
, border
, userData
) );
243 void wxSizer::Add( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
245 m_children
.Append( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
248 void wxSizer::Add( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
250 m_children
.Append( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
253 void wxSizer::Prepend( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
255 m_children
.Insert( new wxSizerItem( window
, option
, flag
, border
, userData
) );
258 void wxSizer::Prepend( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
260 m_children
.Insert( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
263 void wxSizer::Prepend( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
265 m_children
.Insert( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
268 bool wxSizer::Remove( wxWindow
*window
)
272 wxNode
*node
= m_children
.First();
275 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
276 if (item
->GetWindow() == window
)
278 m_children
.DeleteNode( node
);
287 bool wxSizer::Remove( wxSizer
*sizer
)
291 wxNode
*node
= m_children
.First();
294 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
295 if (item
->GetSizer() == sizer
)
297 m_children
.DeleteNode( node
);
306 bool wxSizer::Remove( int pos
)
308 wxNode
*node
= m_children
.Nth( pos
);
309 if (!node
) return FALSE
;
311 m_children
.DeleteNode( node
);
316 void wxSizer::Fit( wxWindow
*window
)
318 window
->SetSize( GetMinWindowSize( window
) );
321 void wxSizer::Layout()
327 void wxSizer::SetSizeHints( wxWindow
*window
)
329 wxSize
size( GetMinWindowSize( window
) );
330 window
->SetSizeHints( size
.x
, size
.y
);
333 wxSize
wxSizer::GetMinWindowSize( wxWindow
*window
)
335 wxSize
minSize( GetMinSize() );
336 wxSize
size( window
->GetSize() );
337 wxSize
client_size( window
->GetClientSize() );
338 return wxSize( minSize
.x
+size
.x
-client_size
.x
,
339 minSize
.y
+size
.y
-client_size
.y
);
342 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
352 //---------------------------------------------------------------------------
354 //---------------------------------------------------------------------------
356 wxBoxSizer::wxBoxSizer( int orient
)
361 void wxBoxSizer::RecalcSizes()
363 if (m_children
.GetCount() == 0)
370 if (m_orient
== wxHORIZONTAL
)
372 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
373 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
377 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
378 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
382 wxPoint
pt( m_position
);
384 wxNode
*node
= m_children
.GetFirst();
387 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
390 if (item
->GetOption())
391 weight
= item
->GetOption();
393 wxSize
size( item
->CalcMin() );
395 if (m_orient
== wxVERTICAL
)
397 long height
= size
.y
;
398 if (item
->GetOption())
400 height
= (delta
* weight
) + extra
;
401 extra
= 0; // only the first item will get the remainder as extra size
404 wxPoint
child_pos( pt
);
405 wxSize
child_size( wxSize( size
.x
, height
) );
407 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
408 child_size
.x
= m_size
.x
;
409 else if (item
->GetFlag() & wxALIGN_RIGHT
)
410 child_pos
.x
+= m_size
.x
- size
.x
;
411 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
412 // XXX wxCENTER is added for backward compatibility;
413 // wxALIGN_CENTER should be used in new code
414 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
416 item
->SetDimension( child_pos
, child_size
);
423 if (item
->GetOption())
425 width
= (delta
* weight
) + extra
;
426 extra
= 0; // only the first item will get the remainder as extra size
429 wxPoint
child_pos( pt
);
430 wxSize
child_size( wxSize(width
, size
.y
) );
432 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
433 child_size
.y
= m_size
.y
;
434 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
435 child_pos
.y
+= m_size
.y
- size
.y
;
436 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
437 // XXX wxCENTER is added for backward compatibility;
438 // wxALIGN_CENTER should be used in new code
439 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
441 item
->SetDimension( child_pos
, child_size
);
450 wxSize
wxBoxSizer::CalcMin()
452 if (m_children
.GetCount() == 0)
461 wxNode
*node
= m_children
.GetFirst();
464 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
467 if (item
->GetOption())
468 weight
= item
->GetOption();
470 wxSize
size( item
->CalcMin() );
472 if (m_orient
== wxHORIZONTAL
)
474 m_minWidth
+= (size
.x
* weight
);
475 m_minHeight
= wxMax( m_minHeight
, size
.y
);
479 m_minHeight
+= (size
.y
* weight
);
480 m_minWidth
= wxMax( m_minWidth
, size
.x
);
483 if (item
->GetOption())
485 m_stretchable
+= weight
;
489 if (m_orient
== wxVERTICAL
)
491 m_fixedHeight
+= size
.y
;
492 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
496 m_fixedWidth
+= size
.x
;
497 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
504 return wxSize( m_minWidth
, m_minHeight
);
507 //---------------------------------------------------------------------------
509 //---------------------------------------------------------------------------
511 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
512 : wxBoxSizer( orient
)
514 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
519 void wxStaticBoxSizer::RecalcSizes()
521 // this will have to be done platform by platform
522 // as there is no way to guess the thickness of
523 // a wxStaticBox border
525 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
526 int other_border
= 5;
528 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
530 wxPoint
old_pos( m_position
);
531 m_position
.x
+= other_border
;
532 m_position
.y
+= top_border
;
533 wxSize
old_size( m_size
);
534 m_size
.x
-= 2*other_border
;
535 m_size
.y
-= top_border
+ other_border
;
537 wxBoxSizer::RecalcSizes();
539 m_position
= old_pos
;
543 wxSize
wxStaticBoxSizer::CalcMin()
545 // this will have to be done platform by platform
546 // as there is no way to guess the thickness of
547 // a wxStaticBox border
549 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
550 int other_border
= 5;
552 wxSize
ret( wxBoxSizer::CalcMin() );
553 ret
.x
+= 2*top_border
;
554 ret
.y
+= other_border
+ top_border
;