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
);
35 IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer
, wxSizer
);
38 //---------------------------------------------------------------------------
40 //---------------------------------------------------------------------------
42 wxSizerItem::wxSizerItem( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
44 m_window
= (wxWindow
*) NULL
;
45 m_sizer
= (wxSizer
*) NULL
;
49 m_userData
= userData
;
51 // minimal size is the initial size
55 SetRatio(width
, height
);
57 // size is set directly
61 wxSizerItem::wxSizerItem( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
64 m_sizer
= (wxSizer
*) NULL
;
68 m_userData
= userData
;
70 // minimal size is the initial size
71 m_minSize
= window
->GetSize();
73 // aspect ratio calculated from initial size
76 // size is calculated later
80 wxSizerItem::wxSizerItem( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
82 m_window
= (wxWindow
*) NULL
;
87 m_userData
= userData
;
89 // minimal size is calculated later
93 // size is calculated later
97 wxSizerItem::~wxSizerItem()
106 wxSize
wxSizerItem::GetSize()
110 ret
= m_sizer
->GetSize();
113 ret
= m_window
->GetSize();
120 if (m_flag
& wxNORTH
)
122 if (m_flag
& wxSOUTH
)
128 wxSize
wxSizerItem::CalcMin()
133 ret
= m_sizer
->CalcMin();
134 // if we have to preserve aspect ratio _AND_ this is
135 // the first-time calculation, consider ret to be initial size
136 if ((m_flag
& wxSHAPED
) && !m_ratio
) SetRatio(ret
);
140 The minimum size of a window should be the
141 initial size, as saved in m_minSize, not the
146 ret = m_window->GetSize();
148 else ret
= m_minSize
;
154 if (m_flag
& wxNORTH
)
156 if (m_flag
& wxSOUTH
)
162 void wxSizerItem::SetDimension( wxPoint pos
, wxSize size
)
173 if (m_flag
& wxNORTH
)
178 if (m_flag
& wxSOUTH
)
182 if (m_flag
& wxSHAPED
) {
183 // adjust aspect ratio
184 int rwidth
= (int) (size
.y
* m_ratio
);
185 if (rwidth
> size
.x
) {
187 int rheight
= (int) (size
.x
/ m_ratio
);
188 // add vertical space
189 if (m_flag
& wxALIGN_CENTER_VERTICAL
)
190 pos
.y
+= (size
.y
- rheight
) / 2;
191 else if (m_flag
& wxALIGN_BOTTOM
)
192 pos
.y
+= (size
.y
- rheight
);
193 // use reduced dimensions
195 } else if (rwidth
< size
.x
) {
196 // add horizontal space
197 if (m_flag
& wxALIGN_CENTER_HORIZONTAL
)
198 pos
.x
+= (size
.x
- rwidth
) / 2;
199 else if (m_flag
& wxALIGN_RIGHT
)
200 pos
.x
+= (size
.x
- rwidth
);
206 m_sizer
->SetDimension( pos
.x
, pos
.y
, size
.x
, size
.y
);
209 m_window
->SetSize( pos
.x
, pos
.y
, size
.x
, size
.y
);
214 bool wxSizerItem::IsWindow()
216 return (m_window
!= NULL
);
219 bool wxSizerItem::IsSizer()
221 return (m_sizer
!= NULL
);
224 bool wxSizerItem::IsSpacer()
226 return (m_window
== NULL
) && (m_sizer
== NULL
);
229 //---------------------------------------------------------------------------
231 //---------------------------------------------------------------------------
235 m_children
.DeleteContents( TRUE
);
242 void wxSizer::Add( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
244 m_children
.Append( new wxSizerItem( window
, option
, flag
, border
, userData
) );
247 void wxSizer::Add( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
249 m_children
.Append( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
252 void wxSizer::Add( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
254 m_children
.Append( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
257 void wxSizer::Prepend( wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
259 m_children
.Insert( new wxSizerItem( window
, option
, flag
, border
, userData
) );
262 void wxSizer::Prepend( wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
264 m_children
.Insert( new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
267 void wxSizer::Prepend( int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
269 m_children
.Insert( new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
272 bool wxSizer::Remove( wxWindow
*window
)
276 wxNode
*node
= m_children
.First();
279 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
280 if (item
->GetWindow() == window
)
282 m_children
.DeleteNode( node
);
291 bool wxSizer::Remove( wxSizer
*sizer
)
295 wxNode
*node
= m_children
.First();
298 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
299 if (item
->GetSizer() == sizer
)
301 m_children
.DeleteNode( node
);
310 bool wxSizer::Remove( int pos
)
312 wxNode
*node
= m_children
.Nth( pos
);
313 if (!node
) return FALSE
;
315 m_children
.DeleteNode( node
);
320 void wxSizer::Fit( wxWindow
*window
)
322 window
->SetSize( GetMinWindowSize( window
) );
325 void wxSizer::Layout()
331 void wxSizer::SetSizeHints( wxWindow
*window
)
333 wxSize
size( GetMinWindowSize( window
) );
334 window
->SetSizeHints( size
.x
, size
.y
);
337 wxSize
wxSizer::GetMinWindowSize( wxWindow
*window
)
339 wxSize
minSize( GetMinSize() );
340 wxSize
size( window
->GetSize() );
341 wxSize
client_size( window
->GetClientSize() );
342 return wxSize( minSize
.x
+size
.x
-client_size
.x
,
343 minSize
.y
+size
.y
-client_size
.y
);
346 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
356 //---------------------------------------------------------------------------
358 //---------------------------------------------------------------------------
360 wxBoxSizer::wxBoxSizer( int orient
)
365 void wxBoxSizer::RecalcSizes()
367 if (m_children
.GetCount() == 0)
374 if (m_orient
== wxHORIZONTAL
)
376 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
377 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
381 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
382 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
386 wxPoint
pt( m_position
);
388 wxNode
*node
= m_children
.GetFirst();
391 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
394 if (item
->GetOption())
395 weight
= item
->GetOption();
397 wxSize
size( item
->CalcMin() );
399 if (m_orient
== wxVERTICAL
)
401 long height
= size
.y
;
402 if (item
->GetOption())
404 height
= (delta
* weight
) + extra
;
405 extra
= 0; // only the first item will get the remainder as extra size
408 wxPoint
child_pos( pt
);
409 wxSize
child_size( wxSize( size
.x
, height
) );
411 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
412 child_size
.x
= m_size
.x
;
413 else if (item
->GetFlag() & wxALIGN_RIGHT
)
414 child_pos
.x
+= m_size
.x
- size
.x
;
415 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
416 // XXX wxCENTER is added for backward compatibility;
417 // wxALIGN_CENTER should be used in new code
418 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
420 item
->SetDimension( child_pos
, child_size
);
427 if (item
->GetOption())
429 width
= (delta
* weight
) + extra
;
430 extra
= 0; // only the first item will get the remainder as extra size
433 wxPoint
child_pos( pt
);
434 wxSize
child_size( wxSize(width
, size
.y
) );
436 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
437 child_size
.y
= m_size
.y
;
438 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
439 child_pos
.y
+= m_size
.y
- size
.y
;
440 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
441 // XXX wxCENTER is added for backward compatibility;
442 // wxALIGN_CENTER should be used in new code
443 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
445 item
->SetDimension( child_pos
, child_size
);
454 wxSize
wxBoxSizer::CalcMin()
456 if (m_children
.GetCount() == 0)
465 wxNode
*node
= m_children
.GetFirst();
468 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
471 if (item
->GetOption())
472 weight
= item
->GetOption();
474 wxSize
size( item
->CalcMin() );
476 if (m_orient
== wxHORIZONTAL
)
478 m_minWidth
+= (size
.x
* weight
);
479 m_minHeight
= wxMax( m_minHeight
, size
.y
);
483 m_minHeight
+= (size
.y
* weight
);
484 m_minWidth
= wxMax( m_minWidth
, size
.x
);
487 if (item
->GetOption())
489 m_stretchable
+= weight
;
493 if (m_orient
== wxVERTICAL
)
495 m_fixedHeight
+= size
.y
;
496 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
500 m_fixedWidth
+= size
.x
;
501 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
508 return wxSize( m_minWidth
, m_minHeight
);
511 //---------------------------------------------------------------------------
513 //---------------------------------------------------------------------------
515 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
516 : wxBoxSizer( orient
)
518 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
523 void wxStaticBoxSizer::RecalcSizes()
525 // this will have to be done platform by platform
526 // as there is no way to guess the thickness of
527 // a wxStaticBox border
529 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
530 int other_border
= 5;
532 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
534 wxPoint
old_pos( m_position
);
535 m_position
.x
+= other_border
;
536 m_position
.y
+= top_border
;
537 wxSize
old_size( m_size
);
538 m_size
.x
-= 2*other_border
;
539 m_size
.y
-= top_border
+ other_border
;
541 wxBoxSizer::RecalcSizes();
543 m_position
= old_pos
;
547 wxSize
wxStaticBoxSizer::CalcMin()
549 // This will have to be done platform by platform
550 // as there is no way to guess the thickness of
551 // a wxStaticBox border.
554 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
555 int other_border
= 5;
557 wxSize
ret( wxBoxSizer::CalcMin() );
558 ret
.x
+= 2*top_border
;
559 ret
.y
+= other_border
+ top_border
;
564 //---------------------------------------------------------------------------
566 //---------------------------------------------------------------------------
570 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
572 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
577 void wxNotebookSizer::RecalcSizes()
579 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
582 wxSize
wxNotebookSizer::CalcMin()
584 // This will have to be done platform by platform
585 // as there is no way to guess the thickness of
586 // the wxNotebook tabs and border.
590 if ((m_notebook
->HasFlag(wxNB_RIGHT
)) ||
591 (m_notebook
->HasFlag(wxNB_LEFT
)))
593 borderX
+= 70; // improvements later..
597 borderY
+= 35; // improvements later..
600 if (m_notebook
->GetChildren().GetCount() == 0)
601 return wxSize(borderX
+ 10, borderY
+ 10);
606 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
609 wxWindow
*item
= node
->GetData();
610 wxSizer
*itemsizer
= item
->GetSizer();
614 wxSize
subsize( itemsizer
->CalcMin() );
616 if (subsize
.x
> maxX
) maxX
= subsize
.x
;
617 if (subsize
.y
> maxY
) maxY
= subsize
.y
;
620 node
= node
->GetNext();
623 return wxSize( borderX
+ maxX
, borderY
+ maxY
);
626 #endif // wxUSE_NOTEBOOK