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"
26 #include "wx/notebook.h"
28 //---------------------------------------------------------------------------
30 IMPLEMENT_ABSTRACT_CLASS(wxSizerItem
, wxObject
);
31 IMPLEMENT_ABSTRACT_CLASS(wxSizer
, wxObject
);
32 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer
, wxSizer
);
33 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer
, wxBoxSizer
);
34 IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer
, wxSizer
);
36 //---------------------------------------------------------------------------
38 //---------------------------------------------------------------------------
40 wxSizerItem::wxSizerItem( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
42 m_window
= (wxWindow
*) NULL
;
43 m_sizer
= (wxSizer
*) NULL
;
47 m_userData
= userData
;
49 // minimal size is the initial size
53 SetRatio(width
, height
);
55 // size is set directly
59 wxSizerItem::wxSizerItem( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
62 m_sizer
= (wxSizer
*) NULL
;
66 m_userData
= userData
;
68 // minimal size is the initial size
69 m_minSize
= window
->GetSize();
71 // aspect ratio calculated from initial size
74 // size is calculated later
78 wxSizerItem::wxSizerItem( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
80 m_window
= (wxWindow
*) NULL
;
85 m_userData
= userData
;
87 // minimal size is calculated later
91 // size is calculated later
95 wxSizerItem::~wxSizerItem()
104 wxSize
wxSizerItem::GetSize()
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
->CalcMin();
132 // if we have to preserve aspect ratio _AND_ this is
133 // the first-time calculation, consider ret to be initial size
134 if ((m_flag
& wxSHAPED
) && !m_ratio
) SetRatio(ret
);
138 The minimum size of a window should be the
139 initial size, as saved in m_minSize, not the
144 ret = m_window->GetSize();
146 else ret
= m_minSize
;
152 if (m_flag
& wxNORTH
)
154 if (m_flag
& wxSOUTH
)
160 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size
)
171 if (m_flag
& wxNORTH
)
176 if (m_flag
& wxSOUTH
)
180 if (m_flag
& wxSHAPED
) {
181 // adjust aspect ratio
182 int rwidth
= (int) (size
.y
* m_ratio
);
183 if (rwidth
> size
.x
) {
185 int rheight
= (int) (size
.x
/ m_ratio
);
186 // add vertical space
187 if (m_flag
& wxALIGN_CENTER_VERTICAL
)
188 pos
.y
+= (size
.y
- rheight
) / 2;
189 else if (m_flag
& wxALIGN_BOTTOM
)
190 pos
.y
+= (size
.y
- rheight
);
191 // use reduced dimensions
193 } else if (rwidth
< size
.x
) {
194 // add horizontal space
195 if (m_flag
& wxALIGN_CENTER_HORIZONTAL
)
196 pos
.x
+= (size
.x
- rwidth
) / 2;
197 else if (m_flag
& wxALIGN_RIGHT
)
198 pos
.x
+= (size
.x
- rwidth
);
204 m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y
);
207 m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
);
212 bool wxSizerItem::IsWindow()
214 return (m_window
!= NULL
);
217 bool wxSizerItem::IsSizer()
219 return (m_sizer
!= NULL
);
222 bool wxSizerItem::IsSpacer()
224 return (m_window
== NULL
) && (m_sizer
== NULL
);
227 //---------------------------------------------------------------------------
229 //---------------------------------------------------------------------------
233 m_children
.DeleteContents( TRUE
);
240 void wxSizer::Add( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
242 m_children
.Append( new wxSizerItem( window
, option
, flag
, border
, userData
) );
245 void wxSizer::Add( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
247 m_children
.Append( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
250 void wxSizer::Add( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
252 m_children
.Append( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
255 void wxSizer::Prepend( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
257 m_children
.Insert( new wxSizerItem( window
, option
, flag
, border
, userData
) );
260 void wxSizer::Prepend( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
262 m_children
.Insert( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
265 void wxSizer::Prepend( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
267 m_children
.Insert( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
270 bool wxSizer::Remove( wxWindow
*window
)
274 wxNode
*node
= m_children
.First();
277 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
278 if (item
->GetWindow() == window
)
280 m_children
.DeleteNode( node
);
289 bool wxSizer::Remove( wxSizer
*sizer
)
293 wxNode
*node
= m_children
.First();
296 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
297 if (item
->GetSizer() == sizer
)
299 m_children
.DeleteNode( node
);
308 bool wxSizer::Remove( int pos
)
310 wxNode
*node
= m_children
.Nth( pos
);
311 if (!node
) return FALSE
;
313 m_children
.DeleteNode( node
);
318 void wxSizer::Fit( wxWindow
*window
)
320 window
->SetSize( GetMinWindowSize( window
) );
323 void wxSizer::Layout()
329 void wxSizer::SetSizeHints( wxWindow
*window
)
331 wxSize
size( GetMinWindowSize( window
) );
332 window
->SetSizeHints( size
.x
, size
.y
);
335 wxSize
wxSizer::GetMinWindowSize( wxWindow
*window
)
337 wxSize
minSize( GetMinSize() );
338 wxSize
size( window
->GetSize() );
339 wxSize
client_size( window
->GetClientSize() );
340 return wxSize( minSize
.x
+size
.x
-client_size
.x
,
341 minSize
.y
+size
.y
-client_size
.y
);
344 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
354 //---------------------------------------------------------------------------
356 //---------------------------------------------------------------------------
358 wxBoxSizer::wxBoxSizer( int orient
)
363 void wxBoxSizer::RecalcSizes()
365 if (m_children
.GetCount() == 0)
372 if (m_orient
== wxHORIZONTAL
)
374 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
375 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
379 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
380 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
384 wxPoint
pt( m_position
);
386 wxNode
*node
= m_children
.GetFirst();
389 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
392 if (item
->GetOption())
393 weight
= item
->GetOption();
395 wxSize
size( item
->CalcMin() );
397 if (m_orient
== wxVERTICAL
)
399 long height
= size
.y
;
400 if (item
->GetOption())
402 height
= (delta
* weight
) + extra
;
403 extra
= 0; // only the first item will get the remainder as extra size
406 wxPoint
child_pos( pt
);
407 wxSize
child_size( wxSize( size
.x
, height
) );
409 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
410 child_size
.x
= m_size
.x
;
411 else if (item
->GetFlag() & wxALIGN_RIGHT
)
412 child_pos
.x
+= m_size
.x
- size
.x
;
413 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
414 // XXX wxCENTER is added for backward compatibility;
415 // wxALIGN_CENTER should be used in new code
416 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
418 item
->SetDimension( child_pos
, child_size
);
425 if (item
->GetOption())
427 width
= (delta
* weight
) + extra
;
428 extra
= 0; // only the first item will get the remainder as extra size
431 wxPoint
child_pos( pt
);
432 wxSize
child_size( wxSize(width
, size
.y
) );
434 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
435 child_size
.y
= m_size
.y
;
436 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
437 child_pos
.y
+= m_size
.y
- size
.y
;
438 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
439 // XXX wxCENTER is added for backward compatibility;
440 // wxALIGN_CENTER should be used in new code
441 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
443 item
->SetDimension( child_pos
, child_size
);
452 wxSize
wxBoxSizer::CalcMin()
454 if (m_children
.GetCount() == 0)
463 wxNode
*node
= m_children
.GetFirst();
466 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
469 if (item
->GetOption())
470 weight
= item
->GetOption();
472 wxSize
size( item
->CalcMin() );
474 if (m_orient
== wxHORIZONTAL
)
476 m_minWidth
+= (size
.x
* weight
);
477 m_minHeight
= wxMax( m_minHeight
, size
.y
);
481 m_minHeight
+= (size
.y
* weight
);
482 m_minWidth
= wxMax( m_minWidth
, size
.x
);
485 if (item
->GetOption())
487 m_stretchable
+= weight
;
491 if (m_orient
== wxVERTICAL
)
493 m_fixedHeight
+= size
.y
;
494 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
498 m_fixedWidth
+= size
.x
;
499 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
506 return wxSize( m_minWidth
, m_minHeight
);
509 //---------------------------------------------------------------------------
511 //---------------------------------------------------------------------------
513 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
514 : wxBoxSizer( orient
)
516 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
521 void wxStaticBoxSizer::RecalcSizes()
523 // this will have to be done platform by platform
524 // as there is no way to guess the thickness of
525 // a wxStaticBox border
527 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
528 int other_border
= 5;
530 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
532 wxPoint
old_pos( m_position
);
533 m_position
.x
+= other_border
;
534 m_position
.y
+= top_border
;
535 wxSize
old_size( m_size
);
536 m_size
.x
-= 2*other_border
;
537 m_size
.y
-= top_border
+ other_border
;
539 wxBoxSizer::RecalcSizes();
541 m_position
= old_pos
;
545 wxSize
wxStaticBoxSizer::CalcMin()
547 // This will have to be done platform by platform
548 // as there is no way to guess the thickness of
549 // a wxStaticBox border.
552 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
553 int other_border
= 5;
555 wxSize
ret( wxBoxSizer::CalcMin() );
556 ret
.x
+= 2*top_border
;
557 ret
.y
+= other_border
+ top_border
;
562 //---------------------------------------------------------------------------
564 //---------------------------------------------------------------------------
566 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
568 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
573 void wxNotebookSizer::RecalcSizes()
575 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
578 wxSize
wxNotebookSizer::CalcMin()
580 // This will have to be done platform by platform
581 // as there is no way to guess the thickness of
582 // the wxNotebook tabs and border.
586 if ((m_notebook
->HasFlag(wxNB_RIGHT
)) ||
587 (m_notebook
->HasFlag(wxNB_LEFT
)))
589 borderX
+= 70; // improvements later..
593 borderY
+= 35; // improvements later..
596 if (m_notebook
->GetChildren().GetCount() == 0)
597 return wxSize(borderX
+ 10, borderY
+ 10);
602 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
605 wxWindow
*item
= node
->GetData();
606 wxSizer
*itemsizer
= item
->GetSizer();
610 wxSize
subsize( itemsizer
->CalcMin() );
612 if (subsize
.x
> maxX
) maxX
= subsize
.x
;
613 if (subsize
.y
> maxY
) maxY
= subsize
.y
;
616 node
= node
->GetNext();
619 return wxSize( borderX
+ maxX
, borderY
+ maxY
);