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 void wxSizer::Insert( int before
, wxWindow
*window
, int option
, int flag
, int border
, wxObject
* userData
)
274 m_children
.Insert( before
, new wxSizerItem( window
, option
, flag
, border
, userData
) );
277 void wxSizer::Insert( int before
, wxSizer
*sizer
, int option
, int flag
, int border
, wxObject
* userData
)
279 m_children
.Insert( before
, new wxSizerItem( sizer
, option
, flag
, border
, userData
) );
282 void wxSizer::Insert( int before
, int width
, int height
, int option
, int flag
, int border
, wxObject
* userData
)
284 m_children
.Insert( before
, new wxSizerItem( width
, height
, option
, flag
, border
, userData
) );
287 bool wxSizer::Remove( wxWindow
*window
)
291 wxNode
*node
= m_children
.First();
294 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
295 if (item
->GetWindow() == window
)
297 m_children
.DeleteNode( node
);
306 bool wxSizer::Remove( wxSizer
*sizer
)
310 wxNode
*node
= m_children
.First();
313 wxSizerItem
*item
= (wxSizerItem
*)node
->Data();
314 if (item
->GetSizer() == sizer
)
316 m_children
.DeleteNode( node
);
325 bool wxSizer::Remove( int pos
)
327 wxNode
*node
= m_children
.Nth( pos
);
328 if (!node
) return FALSE
;
330 m_children
.DeleteNode( node
);
335 void wxSizer::Fit( wxWindow
*window
)
337 window
->SetSize( GetMinWindowSize( window
) );
340 void wxSizer::Layout()
346 void wxSizer::SetSizeHints( wxWindow
*window
)
348 wxSize
size( GetMinWindowSize( window
) );
349 window
->SetSizeHints( size
.x
, size
.y
);
352 wxSize
wxSizer::GetMinWindowSize( wxWindow
*window
)
354 wxSize
minSize( GetMinSize() );
355 wxSize
size( window
->GetSize() );
356 wxSize
client_size( window
->GetClientSize() );
357 return wxSize( minSize
.x
+size
.x
-client_size
.x
,
358 minSize
.y
+size
.y
-client_size
.y
);
361 void wxSizer::SetDimension( int x
, int y
, int width
, int height
)
371 //---------------------------------------------------------------------------
373 //---------------------------------------------------------------------------
375 wxBoxSizer::wxBoxSizer( int orient
)
380 void wxBoxSizer::RecalcSizes()
382 if (m_children
.GetCount() == 0)
389 if (m_orient
== wxHORIZONTAL
)
391 delta
= (m_size
.x
- m_fixedWidth
) / m_stretchable
;
392 extra
= (m_size
.x
- m_fixedWidth
) % m_stretchable
;
396 delta
= (m_size
.y
- m_fixedHeight
) / m_stretchable
;
397 extra
= (m_size
.y
- m_fixedHeight
) % m_stretchable
;
401 wxPoint
pt( m_position
);
403 wxNode
*node
= m_children
.GetFirst();
406 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
409 if (item
->GetOption())
410 weight
= item
->GetOption();
412 wxSize
size( item
->CalcMin() );
414 if (m_orient
== wxVERTICAL
)
416 long height
= size
.y
;
417 if (item
->GetOption())
419 height
= (delta
* weight
) + extra
;
420 extra
= 0; // only the first item will get the remainder as extra size
423 wxPoint
child_pos( pt
);
424 wxSize
child_size( wxSize( size
.x
, height
) );
426 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
427 child_size
.x
= m_size
.x
;
428 else if (item
->GetFlag() & wxALIGN_RIGHT
)
429 child_pos
.x
+= m_size
.x
- size
.x
;
430 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_HORIZONTAL
))
431 // XXX wxCENTER is added for backward compatibility;
432 // wxALIGN_CENTER should be used in new code
433 child_pos
.x
+= (m_size
.x
- size
.x
) / 2;
435 item
->SetDimension( child_pos
, child_size
);
442 if (item
->GetOption())
444 width
= (delta
* weight
) + extra
;
445 extra
= 0; // only the first item will get the remainder as extra size
448 wxPoint
child_pos( pt
);
449 wxSize
child_size( wxSize(width
, size
.y
) );
451 if (item
->GetFlag() & (wxEXPAND
| wxSHAPED
))
452 child_size
.y
= m_size
.y
;
453 else if (item
->GetFlag() & wxALIGN_BOTTOM
)
454 child_pos
.y
+= m_size
.y
- size
.y
;
455 else if (item
->GetFlag() & (wxCENTER
| wxALIGN_CENTER_VERTICAL
))
456 // XXX wxCENTER is added for backward compatibility;
457 // wxALIGN_CENTER should be used in new code
458 child_pos
.y
+= (m_size
.y
- size
.y
) / 2;
460 item
->SetDimension( child_pos
, child_size
);
469 wxSize
wxBoxSizer::CalcMin()
471 if (m_children
.GetCount() == 0)
472 return wxSize(10,10);
480 wxNode
*node
= m_children
.GetFirst();
483 wxSizerItem
*item
= (wxSizerItem
*) node
->Data();
486 if (item
->GetOption())
487 weight
= item
->GetOption();
489 wxSize
size( item
->CalcMin() );
491 if (m_orient
== wxHORIZONTAL
)
493 m_minWidth
+= (size
.x
* weight
);
494 m_minHeight
= wxMax( m_minHeight
, size
.y
);
498 m_minHeight
+= (size
.y
* weight
);
499 m_minWidth
= wxMax( m_minWidth
, size
.x
);
502 if (item
->GetOption())
504 m_stretchable
+= weight
;
508 if (m_orient
== wxVERTICAL
)
510 m_fixedHeight
+= size
.y
;
511 m_fixedWidth
= wxMax( m_fixedWidth
, size
.x
);
515 m_fixedWidth
+= size
.x
;
516 m_fixedHeight
= wxMax( m_fixedHeight
, size
.y
);
523 return wxSize( m_minWidth
, m_minHeight
);
526 //---------------------------------------------------------------------------
528 //---------------------------------------------------------------------------
530 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox
*box
, int orient
)
531 : wxBoxSizer( orient
)
533 wxASSERT_MSG( box
, wxT("wxStaticBoxSizer needs a static box") );
538 void wxStaticBoxSizer::RecalcSizes()
540 // this will have to be done platform by platform
541 // as there is no way to guess the thickness of
542 // a wxStaticBox border
544 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
545 int other_border
= 5;
547 m_staticBox
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
549 wxPoint
old_pos( m_position
);
550 m_position
.x
+= other_border
;
551 m_position
.y
+= top_border
;
552 wxSize
old_size( m_size
);
553 m_size
.x
-= 2*other_border
;
554 m_size
.y
-= top_border
+ other_border
;
556 wxBoxSizer::RecalcSizes();
558 m_position
= old_pos
;
562 wxSize
wxStaticBoxSizer::CalcMin()
564 // This will have to be done platform by platform
565 // as there is no way to guess the thickness of
566 // a wxStaticBox border.
569 if (m_staticBox
->GetLabel().IsEmpty()) top_border
= 5;
570 int other_border
= 5;
572 wxSize
ret( wxBoxSizer::CalcMin() );
573 ret
.x
+= 2*other_border
;
574 ret
.y
+= other_border
+ top_border
;
579 //---------------------------------------------------------------------------
581 //---------------------------------------------------------------------------
585 wxNotebookSizer::wxNotebookSizer( wxNotebook
*nb
)
587 wxASSERT_MSG( nb
, wxT("wxNotebookSizer needs a notebook") );
592 void wxNotebookSizer::RecalcSizes()
594 m_notebook
->SetSize( m_position
.x
, m_position
.y
, m_size
.x
, m_size
.y
);
597 wxSize
wxNotebookSizer::CalcMin()
599 // This will have to be done platform by platform
600 // as there is no way to guess the thickness of
601 // the wxNotebook tabs and border.
605 if ((m_notebook
->HasFlag(wxNB_RIGHT
)) ||
606 (m_notebook
->HasFlag(wxNB_LEFT
)))
608 borderX
+= 70; // improvements later..
612 borderY
+= 35; // improvements later..
615 if (m_notebook
->GetChildren().GetCount() == 0)
616 return wxSize(borderX
+ 10, borderY
+ 10);
621 wxWindowList::Node
*node
= m_notebook
->GetChildren().GetFirst();
624 wxWindow
*item
= node
->GetData();
625 wxSizer
*itemsizer
= item
->GetSizer();
629 wxSize
subsize( itemsizer
->CalcMin() );
631 if (subsize
.x
> maxX
) maxX
= subsize
.x
;
632 if (subsize
.y
> maxY
) maxY
= subsize
.y
;
635 node
= node
->GetNext();
638 return wxSize( borderX
+ maxX
, borderY
+ maxY
);
641 #endif // wxUSE_NOTEBOOK