]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
fix bug in Borland (bcc32 really hates ?)
[wxWidgets.git] / src / common / sizer.cpp
CommitLineData
5279a24d
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: sizer.cpp
1044a386 3// Purpose: provide new wxSizer class for layout
aa5973ee
JS
4// Author: Robert Roebling and Robin Dunn, contributions by
5// Dirk Holtwick, Ron Lee
566d84a7 6// Modified by: Ron Lee
0c0d686f 7// Created:
5279a24d 8// RCS-ID: $Id$
aa5973ee 9// Copyright: (c) Robin Dunn, Robert Roebling
5279a24d
RR
10// Licence: wxWindows licence
11/////////////////////////////////////////////////////////////////////////////
12
5279a24d 13#ifdef __GNUG__
c62ac5b6 14#pragma implementation "sizer.h"
5279a24d
RR
15#endif
16
77671fd2
VZ
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
21 #pragma hdrstop
22#endif
23
5279a24d 24#include "wx/sizer.h"
61d514bb 25#include "wx/utils.h"
27ea1d8a 26#include "wx/statbox.h"
83edc0a5 27#include "wx/notebook.h"
12a3f227 28#include <wx/listimpl.cpp>
5279a24d 29
0c0d686f
RD
30//---------------------------------------------------------------------------
31
9cbee2ce
RL
32IMPLEMENT_CLASS(wxSizerItem, wxObject)
33IMPLEMENT_CLASS(wxSizer, wxObject)
34IMPLEMENT_CLASS(wxGridSizer, wxSizer)
35IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
36IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
1e6feb95 37#if wxUSE_STATBOX
9cbee2ce 38IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
1e6feb95 39#endif
60be2f47 40#if wxUSE_NOTEBOOK
9cbee2ce 41IMPLEMENT_CLASS(wxNotebookSizer, wxSizer)
60be2f47 42#endif
0c0d686f 43
12a3f227
RL
44WX_DEFINE_EXPORTED_LIST( wxSizerItemList );
45
46
5279a24d 47//---------------------------------------------------------------------------
3417c2cd 48// wxSizerItem
5279a24d
RR
49//---------------------------------------------------------------------------
50
12a3f227
RL
51wxSizerItem::wxSizerItem( int width, int height, int proportion, int flag, int border, wxObject* userData )
52 : m_window( NULL )
53 , m_sizer( NULL )
00976fe5
RL
54 , m_size( wxSize( width, height ) ) // size is set directly
55 , m_minSize( m_size ) // minimal size is the initial size
12a3f227 56 , m_proportion( proportion )
00976fe5
RL
57 , m_border( border )
58 , m_flag( flag )
e0d8fb45 59 , m_show( true )
00976fe5 60 , m_userData( userData )
5279a24d 61{
00976fe5 62 SetRatio( m_size );
5279a24d
RR
63}
64
12a3f227 65wxSizerItem::wxSizerItem( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
00976fe5 66 : m_window( window )
12a3f227 67 , m_sizer( NULL )
00976fe5 68 , m_minSize( window->GetSize() ) // minimal size is the initial size
12a3f227 69 , m_proportion( proportion )
00976fe5
RL
70 , m_border( border )
71 , m_flag( flag )
e0d8fb45 72 , m_show( true )
00976fe5 73 , m_userData( userData )
5279a24d 74{
be2577e4 75 // aspect ratio calculated from initial size
00976fe5 76 SetRatio( m_minSize );
be2577e4 77
00976fe5 78 // m_size is calculated later
5279a24d
RR
79}
80
12a3f227
RL
81wxSizerItem::wxSizerItem( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
82 : m_window( NULL )
00976fe5 83 , m_sizer( sizer )
12a3f227 84 , m_proportion( proportion )
00976fe5
RL
85 , m_border( border )
86 , m_flag( flag )
e0d8fb45 87 , m_show( true )
12a3f227 88 , m_ratio( 0.0 )
00976fe5 89 , m_userData( userData )
5279a24d 90{
00976fe5
RL
91 // m_minSize is calculated later
92 // m_size is calculated later
5279a24d
RR
93}
94
0c0d686f
RD
95wxSizerItem::~wxSizerItem()
96{
97 if (m_userData)
98 delete m_userData;
96fdbb60 99 if (m_sizer)
0c0d686f
RD
100 delete m_sizer;
101}
102
103
9cbee2ce 104wxSize wxSizerItem::GetSize() const
5279a24d 105{
d597fcb7 106 wxSize ret;
3417c2cd 107 if (IsSizer())
d597fcb7
RR
108 ret = m_sizer->GetSize();
109 else
c62ac5b6 110 if (IsWindow())
d597fcb7
RR
111 ret = m_window->GetSize();
112 else ret = m_size;
0c0d686f 113
d597fcb7
RR
114 if (m_flag & wxWEST)
115 ret.x += m_border;
116 if (m_flag & wxEAST)
117 ret.x += m_border;
118 if (m_flag & wxNORTH)
119 ret.y += m_border;
120 if (m_flag & wxSOUTH)
121 ret.y += m_border;
0c0d686f 122
d597fcb7 123 return ret;
5279a24d
RR
124}
125
3417c2cd 126wxSize wxSizerItem::CalcMin()
c62ac5b6 127{
d597fcb7 128 wxSize ret;
3417c2cd 129 if (IsSizer())
be2577e4 130 {
f6bcfd97 131 ret = m_sizer->GetMinSize();
d13d8d4e 132
be2577e4
RD
133 // if we have to preserve aspect ratio _AND_ this is
134 // the first-time calculation, consider ret to be initial size
d13d8d4e
VZ
135 if ((m_flag & wxSHAPED) && !m_ratio)
136 SetRatio(ret);
be2577e4 137 }
d597fcb7 138 else
d13d8d4e
VZ
139 {
140 if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
141 {
2b5f62a0
VZ
142 // By user request, keep the minimal size for this item
143 // in sync with the largest of BestSize and any user supplied
144 // minimum size hint. Useful in cases where the item is
145 // changeable -- static text labels, etc.
146 m_minSize = m_window->GetAdjustedBestSize();
d13d8d4e
VZ
147 }
148
149 ret = m_minSize;
150 }
0c0d686f 151
d597fcb7
RR
152 if (m_flag & wxWEST)
153 ret.x += m_border;
154 if (m_flag & wxEAST)
155 ret.x += m_border;
156 if (m_flag & wxNORTH)
157 ret.y += m_border;
158 if (m_flag & wxSOUTH)
159 ret.y += m_border;
0c0d686f 160
d597fcb7 161 return ret;
c62ac5b6
RR
162}
163
3417c2cd 164void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
c62ac5b6 165{
cdddaeea 166 if (m_flag & wxSHAPED)
d597fcb7 167 {
be2577e4
RD
168 // adjust aspect ratio
169 int rwidth = (int) (size.y * m_ratio);
cdddaeea
VZ
170 if (rwidth > size.x)
171 {
be2577e4
RD
172 // fit horizontally
173 int rheight = (int) (size.x / m_ratio);
174 // add vertical space
175 if (m_flag & wxALIGN_CENTER_VERTICAL)
176 pos.y += (size.y - rheight) / 2;
177 else if (m_flag & wxALIGN_BOTTOM)
178 pos.y += (size.y - rheight);
179 // use reduced dimensions
180 size.y =rheight;
cdddaeea
VZ
181 }
182 else if (rwidth < size.x)
183 {
be2577e4
RD
184 // add horizontal space
185 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
186 pos.x += (size.x - rwidth) / 2;
187 else if (m_flag & wxALIGN_RIGHT)
188 pos.x += (size.x - rwidth);
189 size.x = rwidth;
190 }
191 }
33ac7e6f 192
cdddaeea
VZ
193 // This is what GetPosition() returns. Since we calculate
194 // borders afterwards, GetPosition() will be the left/top
195 // corner of the surrounding border.
196 m_pos = pos;
197
198 if (m_flag & wxWEST)
199 {
200 pos.x += m_border;
201 size.x -= m_border;
202 }
203 if (m_flag & wxEAST)
204 {
205 size.x -= m_border;
206 }
207 if (m_flag & wxNORTH)
208 {
209 pos.y += m_border;
210 size.y -= m_border;
211 }
212 if (m_flag & wxSOUTH)
213 {
214 size.y -= m_border;
215 }
0c0d686f 216
3417c2cd 217 if (IsSizer())
c62ac5b6 218 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
0c0d686f 219
c62ac5b6 220 if (IsWindow())
b919f007 221 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
d597fcb7
RR
222
223 m_size = size;
c62ac5b6
RR
224}
225
84f7908b
RR
226void wxSizerItem::DeleteWindows()
227{
228 if (m_window)
229 m_window->Destroy();
be90c029 230
84f7908b
RR
231 if (m_sizer)
232 m_sizer->DeleteWindows();
233}
234
9cbee2ce 235bool wxSizerItem::IsWindow() const
5279a24d
RR
236{
237 return (m_window != NULL);
238}
239
9cbee2ce 240bool wxSizerItem::IsSizer() const
5279a24d
RR
241{
242 return (m_sizer != NULL);
243}
244
9cbee2ce 245bool wxSizerItem::IsSpacer() const
5279a24d
RR
246{
247 return (m_window == NULL) && (m_sizer == NULL);
248}
249
12a3f227
RL
250void wxSizerItem::Show( bool show )
251{
252 m_show = show;
253
254 if( IsWindow() )
255 m_window->Show( show );
256 else if( IsSizer() )
257 m_sizer->ShowItems( show );
258
259 // ... nothing else to do to hide/show spacers
260}
261
262void wxSizerItem::SetOption( int option )
263{
264 SetProportion( option );
265}
266
267int wxSizerItem::GetOption() const
268{
269 return GetProportion();
270}
271
272
5279a24d 273//---------------------------------------------------------------------------
3417c2cd 274// wxSizer
5279a24d
RR
275//---------------------------------------------------------------------------
276
3417c2cd 277wxSizer::wxSizer()
12a3f227 278 : m_minSize( wxSize( 0, 0 ) )
5279a24d 279{
e0d8fb45 280 m_children.DeleteContents( true );
5279a24d
RR
281}
282
3417c2cd 283wxSizer::~wxSizer()
5279a24d 284{
be90c029 285 Clear();
5279a24d 286}
0c0d686f 287
12a3f227 288void wxSizer::Add( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
5279a24d 289{
12a3f227
RL
290 m_children.Append( new wxSizerItem( window, proportion, flag, border, userData ) );
291 window->SetContainingSizer( this );
5279a24d
RR
292}
293
12a3f227 294void wxSizer::Add( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
5279a24d 295{
12a3f227 296 m_children.Append( new wxSizerItem( sizer, proportion, flag, border, userData ) );
5279a24d
RR
297}
298
12a3f227 299void wxSizer::Add( int width, int height, int proportion, int flag, int border, wxObject* userData )
5279a24d 300{
12a3f227 301 m_children.Append( new wxSizerItem( width, height, proportion, flag, border, userData ) );
5279a24d
RR
302}
303
12a3f227 304void wxSizer::Add( wxSizerItem *item )
42b4e99e 305{
12a3f227
RL
306 m_children.Append( item );
307
308 if( item->GetWindow() )
309 item->GetWindow()->SetContainingSizer( this );
42b4e99e
RR
310}
311
12a3f227 312void wxSizer::Prepend( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
42b4e99e 313{
12a3f227
RL
314 m_children.Insert( new wxSizerItem( window, proportion, flag, border, userData ) );
315 window->SetContainingSizer( this );
42b4e99e
RR
316}
317
12a3f227 318void wxSizer::Prepend( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
42b4e99e 319{
12a3f227 320 m_children.Insert( new wxSizerItem( sizer, proportion, flag, border, userData ) );
f35aa3da
RR
321}
322
12a3f227 323void wxSizer::Prepend( int width, int height, int proportion, int flag, int border, wxObject* userData )
f35aa3da 324{
12a3f227 325 m_children.Insert( new wxSizerItem( width, height, proportion, flag, border, userData ) );
f35aa3da
RR
326}
327
12a3f227 328void wxSizer::Prepend( wxSizerItem *item )
f35aa3da 329{
12a3f227
RL
330 m_children.Insert( item );
331
332 if( item->GetWindow() )
333 item->GetWindow()->SetContainingSizer( this );
f35aa3da
RR
334}
335
12a3f227
RL
336void wxSizer::Insert( size_t index,
337 wxWindow *window,
338 int proportion,
339 int flag,
340 int border,
341 wxObject* userData )
f35aa3da 342{
12a3f227
RL
343 m_children.Insert( index,
344 new wxSizerItem( window, proportion, flag, border, userData ) );
345 window->SetContainingSizer( this );
42b4e99e
RR
346}
347
12a3f227
RL
348void wxSizer::Insert( size_t index,
349 wxSizer *sizer,
350 int proportion,
351 int flag,
352 int border,
353 wxObject* userData )
42b4e99e 354{
12a3f227
RL
355 m_children.Insert( index,
356 new wxSizerItem( sizer, proportion, flag, border, userData ) );
357}
0c0d686f 358
12a3f227
RL
359void wxSizer::Insert( size_t index,
360 int width,
361 int height,
362 int proportion,
363 int flag,
364 int border,
365 wxObject* userData )
366{
367 m_children.Insert( index,
368 new wxSizerItem( width, height, proportion, flag, border, userData ) );
369}
370
371void wxSizer::Insert( size_t index, wxSizerItem *item )
372{
373 m_children.Insert( index, item );
0c0d686f 374
12a3f227
RL
375 if( item->GetWindow() )
376 item->GetWindow()->SetContainingSizer( this );
377}
378
379bool wxSizer::Remove( wxWindow *window )
380{
381 return Detach( window );
42b4e99e
RR
382}
383
384bool wxSizer::Remove( wxSizer *sizer )
385{
12a3f227 386 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
0c0d686f 387
12a3f227 388 wxSizerItemList::Node *node = m_children.GetFirst();
42b4e99e
RR
389 while (node)
390 {
12a3f227
RL
391 wxSizerItem *item = node->GetData();
392
3ca6a5f0 393 if (item->GetSizer() == sizer)
12a3f227
RL
394 return m_children.DeleteNode( node );
395
396 node = node->GetNext();
42b4e99e 397 }
0c0d686f 398
e0d8fb45 399 return false;
42b4e99e
RR
400}
401
e0d8fb45 402bool wxSizer::Remove( int index )
42b4e99e 403{
e0d8fb45
VZ
404 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
405 false,
12a3f227 406 _T("Remove index is out of range") );
0c0d686f 407
e0d8fb45 408 wxSizerItemList::Node *node = m_children.Item( index );
0c0d686f 409
e0d8fb45 410 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227 411
e0d8fb45 412 wxSizerItem *item = node->GetData();
9cbee2ce
RL
413
414 if( item->IsWindow() )
415 item->GetWindow()->SetContainingSizer( NULL );
416
12a3f227 417 return m_children.DeleteNode( node );
42b4e99e 418}
0c0d686f 419
00976fe5
RL
420bool wxSizer::Detach( wxSizer *sizer )
421{
12a3f227 422 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
00976fe5 423
12a3f227 424 wxSizerItemList::Node *node = m_children.GetFirst();
00976fe5
RL
425 while (node)
426 {
12a3f227
RL
427 wxSizerItem *item = node->GetData();
428
00976fe5
RL
429 if (item->GetSizer() == sizer)
430 {
96fdbb60 431 item->DetachSizer();
12a3f227
RL
432 return m_children.DeleteNode( node );
433 }
434 node = node->GetNext();
435 }
436
e0d8fb45 437 return false;
12a3f227
RL
438}
439
440bool wxSizer::Detach( wxWindow *window )
441{
442 wxASSERT_MSG( window, _T("Detaching NULL window") );
443
444 wxSizerItemList::Node *node = m_children.GetFirst();
445 while (node)
446 {
447 wxSizerItem *item = node->GetData();
448
449 if (item->GetWindow() == window)
450 {
451 item->GetWindow()->SetContainingSizer( NULL );
452 return m_children.DeleteNode( node );
00976fe5 453 }
12a3f227 454 node = node->GetNext();
00976fe5
RL
455 }
456
e0d8fb45 457 return false;
00976fe5
RL
458}
459
e0d8fb45 460bool wxSizer::Detach( int index )
00976fe5 461{
e0d8fb45
VZ
462 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
463 false,
12a3f227
RL
464 _T("Detach index is out of range") );
465
e0d8fb45 466 wxSizerItemList::Node *node = m_children.Item( index );
00976fe5 467
e0d8fb45 468 wxCHECK_MSG( node, false, _T("Failed to find child node") );
00976fe5 469
e0d8fb45 470 wxSizerItem *item = node->GetData();
9cbee2ce
RL
471
472 if( item->IsSizer() )
473 item->DetachSizer();
474 else if( item->IsWindow() )
475 item->GetWindow()->SetContainingSizer( NULL );
12a3f227
RL
476
477 return m_children.DeleteNode( node );
00976fe5
RL
478}
479
84f7908b
RR
480void wxSizer::Clear( bool delete_windows )
481{
be90c029 482 // First clear the ContainingSizer pointers
12a3f227 483 wxSizerItemList::Node *node = m_children.GetFirst();
be90c029
RD
484 while (node)
485 {
12a3f227
RL
486 wxSizerItem *item = node->GetData();
487
be90c029 488 if (item->IsWindow())
12a3f227
RL
489 item->GetWindow()->SetContainingSizer( NULL );
490 node = node->GetNext();
be90c029
RD
491 }
492
493 // Destroy the windows if needed
84f7908b
RR
494 if (delete_windows)
495 DeleteWindows();
be90c029
RD
496
497 // Now empty the list
84f7908b
RR
498 m_children.Clear();
499}
500
501void wxSizer::DeleteWindows()
502{
12a3f227 503 wxSizerItemList::Node *node = m_children.GetFirst();
84f7908b
RR
504 while (node)
505 {
12a3f227
RL
506 wxSizerItem *item = node->GetData();
507
84f7908b 508 item->DeleteWindows();
12a3f227 509 node = node->GetNext();
84f7908b
RR
510 }
511}
512
e5251d4f 513wxSize wxSizer::Fit( wxWindow *window )
5279a24d 514{
9ef2e675
GT
515 wxSize size;
516 if (window->IsTopLevel())
517 size = FitSize( window );
518 else
519 size = GetMinWindowSize( window );
520
77424cfb 521 window->SetSize( size );
e5251d4f
VZ
522
523 return size;
5279a24d
RR
524}
525
566d84a7
RL
526void wxSizer::FitInside( wxWindow *window )
527{
528 wxSize size;
529 if (window->IsTopLevel())
530 size = VirtualFitSize( window );
531 else
532 size = GetMinClientSize( window );
533
534 window->SetVirtualSize( size );
535}
536
3417c2cd 537void wxSizer::Layout()
c62ac5b6 538{
42b4e99e 539 CalcMin();
c62ac5b6
RR
540 RecalcSizes();
541}
542
3417c2cd 543void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 544{
34c3ffca
RL
545 // Preserve the window's max size hints, but set the
546 // lower bound according to the sizer calculations.
547
e5251d4f
VZ
548 wxSize size = Fit( window );
549
34c3ffca
RL
550 window->SetSizeHints( size.x,
551 size.y,
552 window->GetMaxWidth(),
553 window->GetMaxHeight() );
5279a24d
RR
554}
555
566d84a7
RL
556void wxSizer::SetVirtualSizeHints( wxWindow *window )
557{
558 // Preserve the window's max size hints, but set the
559 // lower bound according to the sizer calculations.
560
561 FitInside( window );
562 wxSize size( window->GetVirtualSize() );
563 window->SetVirtualSizeHints( size.x,
564 size.y,
565 window->GetMaxWidth(),
566 window->GetMaxHeight() );
567}
568
9cbee2ce 569wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
65ba4113 570{
34c3ffca 571 return window->GetMaxSize();
65ba4113
GT
572}
573
3417c2cd 574wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 575{
12a3f227
RL
576 wxSize minSize( GetMinSize() );
577 wxSize size( window->GetSize() );
578 wxSize client_size( window->GetClientSize() );
579
77671fd2 580 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 581 minSize.y+size.y-client_size.y );
5279a24d
RR
582}
583
65ba4113
GT
584// Return a window size that will fit within the screens dimensions
585wxSize wxSizer::FitSize( wxWindow *window )
586{
587 wxSize size = GetMinWindowSize( window );
588 wxSize sizeMax = GetMaxWindowSize( window );
589
34c3ffca
RL
590 // Limit the size if sizeMax != wxDefaultSize
591
592 if ( size.x > sizeMax.x && sizeMax.x != -1 )
65ba4113 593 size.x = sizeMax.x;
34c3ffca 594 if ( size.y > sizeMax.y && sizeMax.y != -1 )
65ba4113
GT
595 size.y = sizeMax.y;
596
597 return size;
598}
599
9cbee2ce 600wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7
RL
601{
602 wxSize maxSize( window->GetMaxSize() );
603
604 if( maxSize != wxDefaultSize )
605 {
606 wxSize size( window->GetSize() );
607 wxSize client_size( window->GetClientSize() );
608
609 return wxSize( maxSize.x + client_size.x - size.x,
610 maxSize.y + client_size.y - size.y );
611 }
612 else
613 return wxDefaultSize;
614}
615
1b0674f7 616wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
617{
618 return GetMinSize(); // Already returns client size.
619}
620
621wxSize wxSizer::VirtualFitSize( wxWindow *window )
622{
623 wxSize size = GetMinClientSize( window );
624 wxSize sizeMax = GetMaxClientSize( window );
625
626 // Limit the size if sizeMax != wxDefaultSize
627
628 if ( size.x > sizeMax.x && sizeMax.x != -1 )
629 size.x = sizeMax.x;
630 if ( size.y > sizeMax.y && sizeMax.y != -1 )
631 size.y = sizeMax.y;
632
633 return size;
634}
635
3417c2cd 636void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
637{
638 m_position.x = x;
639 m_position.y = y;
640 m_size.x = width;
641 m_size.y = height;
2b5f62a0 642 Layout();
5279a24d
RR
643}
644
f6bcfd97 645wxSize wxSizer::GetMinSize()
3ca6a5f0 646{
f6bcfd97
BP
647 wxSize ret( CalcMin() );
648 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
649 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 650 return ret;
f6bcfd97
BP
651}
652
653void wxSizer::DoSetMinSize( int width, int height )
654{
655 m_minSize.x = width;
656 m_minSize.y = height;
657}
658
659bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
660{
12a3f227
RL
661 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
662
663 // Is it our immediate child?
f6bcfd97 664
12a3f227 665 wxSizerItemList::Node *node = m_children.GetFirst();
f6bcfd97
BP
666 while (node)
667 {
12a3f227
RL
668 wxSizerItem *item = node->GetData();
669
3ca6a5f0
BP
670 if (item->GetWindow() == window)
671 {
f6bcfd97 672 item->SetInitSize( width, height );
e0d8fb45 673 return true;
3ca6a5f0 674 }
12a3f227 675 node = node->GetNext();
f6bcfd97
BP
676 }
677
12a3f227
RL
678 // No? Search any subsizers we own then
679
680 node = m_children.GetFirst();
f6bcfd97
BP
681 while (node)
682 {
12a3f227
RL
683 wxSizerItem *item = node->GetData();
684
685 if ( item->GetSizer() &&
686 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 687 {
12a3f227 688 // A child sizer found the requested windw, exit.
e0d8fb45 689 return true;
3ca6a5f0 690 }
12a3f227 691 node = node->GetNext();
f6bcfd97
BP
692 }
693
e0d8fb45 694 return false;
f6bcfd97
BP
695}
696
697bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
698{
12a3f227 699 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 700
12a3f227
RL
701 // Is it our immediate child?
702
703 wxSizerItemList::Node *node = m_children.GetFirst();
f6bcfd97
BP
704 while (node)
705 {
12a3f227
RL
706 wxSizerItem *item = node->GetData();
707
3ca6a5f0
BP
708 if (item->GetSizer() == sizer)
709 {
f6bcfd97 710 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 711 return true;
3ca6a5f0 712 }
12a3f227 713 node = node->GetNext();
f6bcfd97
BP
714 }
715
12a3f227
RL
716 // No? Search any subsizers we own then
717
718 node = m_children.GetFirst();
f6bcfd97
BP
719 while (node)
720 {
12a3f227
RL
721 wxSizerItem *item = node->GetData();
722
723 if ( item->GetSizer() &&
724 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 725 {
12a3f227 726 // A child found the requested sizer, exit.
e0d8fb45 727 return true;
3ca6a5f0 728 }
12a3f227 729 node = node->GetNext();
f6bcfd97
BP
730 }
731
e0d8fb45 732 return false;
f6bcfd97
BP
733}
734
12a3f227 735bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 736{
12a3f227
RL
737 wxSizerItemList::Node *node = m_children.Item( index );
738
e0d8fb45 739 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
740
741 wxSizerItem *item = node->GetData();
f6bcfd97 742
f6bcfd97
BP
743 if (item->GetSizer())
744 {
0ca5105b 745 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
746 item->GetSizer()->DoSetMinSize( width, height );
747 }
748 else
749 {
0ca5105b 750 // ... but the minimal size of spacers and windows in stored in them
f6bcfd97
BP
751 item->SetInitSize( width, height );
752 }
753
e0d8fb45 754 return true;
f6bcfd97
BP
755}
756
12a3f227 757void wxSizer::Show( wxWindow *window, bool show )
2b5f62a0 758{
12a3f227
RL
759 wxASSERT_MSG( window, _T("Show for NULL window") );
760
761 wxSizerItemList::Node *node = m_children.GetFirst();
2b5f62a0
VZ
762 while (node)
763 {
12a3f227 764 wxSizerItem *item = node->GetData();
2b5f62a0 765
12a3f227 766 if (item->GetWindow() == window)
2b5f62a0 767 {
12a3f227
RL
768 item->Show( show );
769 break;
2b5f62a0 770 }
12a3f227 771 node = node->GetNext();
2b5f62a0
VZ
772 }
773}
774
12a3f227 775void wxSizer::Show( wxSizer *sizer, bool show )
2b5f62a0 776{
12a3f227
RL
777 wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
778
779 wxSizerItemList::Node *node = m_children.GetFirst();
2b5f62a0
VZ
780 while (node)
781 {
12a3f227 782 wxSizerItem *item = node->GetData();
2b5f62a0 783
12a3f227 784 if (item->GetSizer() == sizer)
2b5f62a0 785 {
12a3f227
RL
786 item->Show( show );
787 break;
2b5f62a0 788 }
12a3f227 789 node = node->GetNext();
2b5f62a0
VZ
790 }
791}
792
12a3f227 793void wxSizer::Show( size_t index, bool show )
2b5f62a0 794{
12a3f227
RL
795 wxCHECK_RET( index < m_children.GetCount(),
796 _T("Show index is out of range") );
2b5f62a0 797
12a3f227
RL
798 m_children.Item( index )->GetData()->Show( show );
799}
2b5f62a0 800
12a3f227
RL
801void wxSizer::ShowItems( bool show )
802{
803 wxSizerItemList::Node *node = m_children.GetFirst();
804 while (node)
805 {
806 node->GetData()->Show( show );
807 node = node->GetNext();
2b5f62a0
VZ
808 }
809}
810
9cbee2ce 811bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 812{
12a3f227 813 wxSizerItemList::Node *node = m_children.GetFirst();
2b5f62a0
VZ
814 while (node)
815 {
12a3f227 816 wxSizerItem *item = node->GetData();
dc259b79 817
12a3f227 818 if (item->GetWindow() == window)
2b5f62a0
VZ
819 {
820 return item->IsShown();
821 }
12a3f227 822 node = node->GetNext();
2b5f62a0
VZ
823 }
824
12a3f227
RL
825 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
826
e0d8fb45 827 return false;
2b5f62a0
VZ
828}
829
9cbee2ce 830bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 831{
12a3f227 832 wxSizerItemList::Node *node = m_children.GetFirst();
2b5f62a0
VZ
833 while (node)
834 {
12a3f227 835 wxSizerItem *item = node->GetData();
2b5f62a0 836
12a3f227 837 if (item->GetSizer() == sizer)
2b5f62a0
VZ
838 {
839 return item->IsShown();
840 }
12a3f227 841 node = node->GetNext();
2b5f62a0
VZ
842 }
843
12a3f227
RL
844 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
845
e0d8fb45 846 return false;
2b5f62a0
VZ
847}
848
9cbee2ce 849bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
850{
851 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 852 false,
12a3f227
RL
853 _T("IsShown index is out of range") );
854
855 return m_children.Item( index )->GetData()->IsShown();
856}
857
858
f6bcfd97
BP
859//---------------------------------------------------------------------------
860// wxGridSizer
861//---------------------------------------------------------------------------
862
863wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
12a3f227
RL
864 : m_rows( rows )
865 , m_cols( cols )
866 , m_vgap( vgap )
867 , m_hgap( hgap )
f6bcfd97 868{
f6bcfd97
BP
869}
870
871wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
12a3f227
RL
872 : m_rows( 0 )
873 , m_cols( cols )
874 , m_vgap( vgap )
875 , m_hgap( hgap )
f6bcfd97 876{
f6bcfd97
BP
877}
878
0ca5105b 879int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 880{
f6bcfd97 881 int nitems = m_children.GetCount();
2b5f62a0 882 if ( nitems)
0ca5105b
VZ
883 {
884 if ( m_cols )
885 {
886 ncols = m_cols;
887 nrows = (nitems + m_cols - 1) / m_cols;
888 }
889 else if ( m_rows )
890 {
891 ncols = (nitems + m_rows - 1) / m_rows;
892 nrows = m_rows;
893 }
894 else // 0 columns, 0 rows?
895 {
896 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 897
0ca5105b
VZ
898 nrows = ncols = 0;
899 }
900 }
901
902 return nitems;
903}
904
905void wxGridSizer::RecalcSizes()
906{
907 int nitems, nrows, ncols;
908 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
909 return;
f6bcfd97
BP
910
911 wxSize sz( GetSize() );
912 wxPoint pt( GetPosition() );
3ca6a5f0
BP
913
914 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
915 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
916
917 int x = pt.x;
918 for (int c = 0; c < ncols; c++)
919 {
920 int y = pt.y;
921 for (int r = 0; r < nrows; r++)
922 {
923 int i = r * ncols + c;
924 if (i < nitems)
925 {
12a3f227
RL
926 wxSizerItemList::Node *node = m_children.Item( i );
927
928 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 929
12a3f227 930 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
931 }
932 y = y + h + m_vgap;
933 }
934 x = x + w + m_hgap;
935 }
936}
937
938wxSize wxGridSizer::CalcMin()
939{
0ca5105b
VZ
940 int nitems, nrows, ncols;
941 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
942 return wxSize(10, 10);
f6bcfd97 943
4f469fb5 944 // Find the max width and height for any component
f6bcfd97
BP
945 int w = 0;
946 int h = 0;
3ca6a5f0 947
12a3f227 948 wxSizerItemList::Node *node = m_children.GetFirst();
f6bcfd97
BP
949 while (node)
950 {
12a3f227
RL
951 wxSizerItem *item = node->GetData();
952 wxSize sz( item->CalcMin() );
953
f6bcfd97
BP
954 w = wxMax( w, sz.x );
955 h = wxMax( h, sz.y );
3ca6a5f0 956
12a3f227 957 node = node->GetNext();
f6bcfd97 958 }
3ca6a5f0 959
12a3f227
RL
960 return wxSize( ncols * w + (ncols-1) * m_hgap,
961 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
962}
963
964void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
965{
966 wxPoint pt( x,y );
967 wxSize sz( item->CalcMin() );
968 int flag = item->GetFlag();
969
970 if ((flag & wxEXPAND) || (flag & wxSHAPED))
971 {
972 sz = wxSize(w, h);
973 }
974 else
975 {
976 if (flag & wxALIGN_CENTER_HORIZONTAL)
977 {
978 pt.x = x + (w - sz.x) / 2;
979 }
980 else if (flag & wxALIGN_RIGHT)
981 {
982 pt.x = x + (w - sz.x);
983 }
3ca6a5f0 984
f6bcfd97
BP
985 if (flag & wxALIGN_CENTER_VERTICAL)
986 {
987 pt.y = y + (h - sz.y) / 2;
988 }
989 else if (flag & wxALIGN_BOTTOM)
990 {
991 pt.y = y + (h - sz.y);
992 }
993 }
3ca6a5f0 994
f6bcfd97
BP
995 item->SetDimension(pt, sz);
996}
997
998//---------------------------------------------------------------------------
999// wxFlexGridSizer
1000//---------------------------------------------------------------------------
1001
1002wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1003 : wxGridSizer( rows, cols, vgap, hgap ),
1004 m_flexDirection(wxBOTH),
1005 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1006{
f6bcfd97
BP
1007}
1008
1009wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1010 : wxGridSizer( cols, vgap, hgap ),
1011 m_flexDirection(wxBOTH),
1012 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1013{
f6bcfd97 1014}
3ca6a5f0 1015
f6bcfd97
BP
1016wxFlexGridSizer::~wxFlexGridSizer()
1017{
f6bcfd97
BP
1018}
1019
1020void wxFlexGridSizer::RecalcSizes()
1021{
0ca5105b
VZ
1022 int nitems, nrows, ncols;
1023 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
f6bcfd97
BP
1024 return;
1025
f6bcfd97
BP
1026 wxSize sz( GetSize() );
1027 wxSize minsz( CalcMin() );
1028 wxPoint pt( GetPosition() );
1029 int delta;
5d76f462 1030 size_t idx, num;
4f469fb5 1031 wxArrayInt temp;
e8800dcf
VZ
1032 wxArrayInt temp_proportions;
1033 int sum_proportions = 0;
1034 int growable_space = 0;
0ca5105b 1035
5d76f462
VZ
1036 // what to do with the rows? by default, resize them proportionally
1037 if ( (m_flexDirection & wxVERTICAL) ||
1038 (m_growMode == wxFLEX_GROWMODE_SPECIFIED) )
1039 {
1040 // Transfer only those rows into temp which exist in the sizer
1041 // ignoring the superfluous ones. This prevents a segfault when
1042 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
1043 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1044 {
1045 if (m_growableRows[idx] < nrows)
e8800dcf 1046 {
5d76f462 1047 temp.Add( m_growableRows[idx] );
e8800dcf
VZ
1048 temp_proportions.Add( m_growableRowsProportions[idx] );
1049 sum_proportions += m_growableRowsProportions[idx];
1050 growable_space += m_rowHeights[ temp[idx] ];
1051 }
5d76f462
VZ
1052 }
1053
1054 num = temp.GetCount();
4f469fb5 1055
5d76f462
VZ
1056 if ((num > 0) && (sz.y > minsz.y))
1057 {
5d76f462 1058 for (idx = 0; idx < num; idx++)
e8800dcf
VZ
1059 {
1060 delta = (sz.y - minsz.y);
1061 if (sum_proportions == 0)
1062 delta = (delta/num) + m_rowHeights[ temp[idx] ];
1063 else
1064 delta = ((delta+growable_space)*temp_proportions[idx])/
1065 sum_proportions;
1066 m_rowHeights[ temp[idx] ] = delta;
1067 }
5d76f462
VZ
1068 }
1069 temp.Empty();
e8800dcf
VZ
1070 temp_proportions.Empty();
1071 sum_proportions = 0;
1072 growable_space = 0;
5d76f462
VZ
1073 }
1074 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
f6bcfd97 1075 {
5d76f462
VZ
1076 // rounding problem?
1077 for ( int row = 0; row < nrows; ++row )
1078 m_rowHeights[ row ] = sz.y / nrows;
f6bcfd97 1079 }
3ca6a5f0 1080
5d76f462
VZ
1081 // the same logic as above but for the columns
1082 if ( (m_flexDirection & wxHORIZONTAL) ||
1083 (m_growMode == wxFLEX_GROWMODE_SPECIFIED) )
1084 {
1085 // See above
1086 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1087 {
1088 if (m_growableCols[idx] < ncols)
e8800dcf 1089 {
5d76f462 1090 temp.Add( m_growableCols[idx] );
e8800dcf
VZ
1091 temp_proportions.Add( m_growableColsProportions[idx] );
1092 sum_proportions += m_growableColsProportions[idx];
1093 growable_space += m_colWidths[idx];
1094 }
5d76f462
VZ
1095 }
1096
1097 num = temp.GetCount();
0ca5105b 1098
5d76f462
VZ
1099 if ((num > 0) && (sz.x > minsz.x))
1100 {
5d76f462 1101 for (idx = 0; idx < num; idx++)
e8800dcf
VZ
1102 {
1103 delta = (sz.x - minsz.x);
1104 if (sum_proportions == 0)
1105 delta = (delta/num) + m_colWidths[ temp[idx] ];
1106 else
1107 delta = ((delta+growable_space)*temp_proportions[idx])/
1108 sum_proportions;
1109 m_colWidths[ temp[idx] ] = delta;
1110 }
5d76f462
VZ
1111 }
1112 }
1113 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
f6bcfd97 1114 {
5d76f462
VZ
1115 for ( int col=0; col < ncols; ++col )
1116 m_colWidths[ col ] = sz.x / ncols;
f6bcfd97 1117 }
3ca6a5f0 1118
f6bcfd97
BP
1119 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1120
1121 int x = pt.x;
1122 for (int c = 0; c < ncols; c++)
1123 {
1124 int y = pt.y;
1125 for (int r = 0; r < nrows; r++)
1126 {
1127 int i = r * ncols + c;
1128 if (i < nitems)
1129 {
12a3f227
RL
1130 wxSizerItemList::Node *node = m_children.Item( i );
1131
1132 wxASSERT_MSG( node, _T("Failed to find node") );
3ca6a5f0 1133
f6bcfd97
BP
1134 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1135 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
3ca6a5f0 1136
12a3f227 1137 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1138 }
1139 y = y + m_rowHeights[r] + m_vgap;
1140 }
1141 x = x + m_colWidths[c] + m_hgap;
1142 }
1143}
1144
1145wxSize wxFlexGridSizer::CalcMin()
1146{
150c8d89
RL
1147 int nrows,
1148 ncols;
1149 size_t i, s;
1150
5d76f462
VZ
1151 if ( !CalcRowsCols(nrows, ncols) )
1152 return wxSize(10, 10);
f6bcfd97 1153
150c8d89
RL
1154 // We have to clear the old sizes out if any item has wxADJUST_MINSIZE
1155 // set on it. Its probably quicker to just always do it than test for
1156 // that though. At least do it before resizing the arrays, SetCount will
1157 // initialise new elements to zero.
1158 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1159 m_rowHeights[ i ] = 0;
1160
1161 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1162 m_colWidths[ i ] = 0;
1163
5d76f462
VZ
1164 m_rowHeights.SetCount(nrows);
1165 m_colWidths.SetCount(ncols);
3ca6a5f0 1166
12a3f227
RL
1167 wxSizerItemList::Node *node = m_children.GetFirst();
1168
150c8d89 1169 i = 0;
f6bcfd97
BP
1170 while (node)
1171 {
12a3f227
RL
1172 wxSizerItem *item = node->GetData();
1173 wxSize sz( item->CalcMin() );
1174 int row = i / ncols;
1175 int col = i % ncols;
1176
f6bcfd97
BP
1177 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
1178 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
3ca6a5f0 1179
12a3f227 1180 node = node->GetNext();
f6bcfd97
BP
1181 i++;
1182 }
3ca6a5f0 1183
5d76f462
VZ
1184 // the logic above works when we resize flexibly in both directions but
1185 // maybe this is not the case
1186 if ( m_flexDirection != wxBOTH )
1187 {
1188 // select the array corresponding to the direction in which we do *not*
1189 // resize flexibly
1190 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1191 : m_rowHeights;
1192
1193 const int count = array.GetCount();
1194
1195 // find the largest value in this array
1196 int n,
1197 largest = 0;
1198 for ( n = 0; n < count; ++n )
1199 {
1200 if ( array[n] > largest )
1201 largest = array[n];
1202 }
1203
1204 // and now fill it with the largest value
1205 for ( n = 0; n < count; ++n )
1206 {
1207 array[n] = largest;
1208 }
1209 }
1210
1211
f6bcfd97 1212 int width = 0;
0ca5105b 1213 for (int col = 0; col < ncols; col++)
f6bcfd97 1214 width += m_colWidths[ col ];
3ca6a5f0 1215
f6bcfd97 1216 int height = 0;
0ca5105b 1217 for (int row = 0; row < nrows; row++)
f6bcfd97 1218 height += m_rowHeights[ row ];
3ca6a5f0 1219
f6bcfd97
BP
1220 return wxSize( width + (ncols-1) * m_hgap,
1221 height + (nrows-1) * m_vgap);
1222}
1223
e8800dcf 1224void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1225{
1226 m_growableRows.Add( idx );
e8800dcf 1227 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1228}
1229
3ca6a5f0 1230void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
f6bcfd97
BP
1231{
1232}
1233
e8800dcf 1234void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1235{
1236 m_growableCols.Add( idx );
e8800dcf 1237 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1238}
1239
3ca6a5f0 1240void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
f6bcfd97
BP
1241{
1242}
1243
c62ac5b6 1244//---------------------------------------------------------------------------
92afa2b1 1245// wxBoxSizer
61d514bb
RR
1246//---------------------------------------------------------------------------
1247
92afa2b1 1248wxBoxSizer::wxBoxSizer( int orient )
12a3f227 1249 : m_orient( orient )
61d514bb 1250{
61d514bb
RR
1251}
1252
92afa2b1 1253void wxBoxSizer::RecalcSizes()
61d514bb
RR
1254{
1255 if (m_children.GetCount() == 0)
61d514bb 1256 return;
0c0d686f 1257
61d514bb
RR
1258 int delta = 0;
1259 int extra = 0;
1260 if (m_stretchable)
1261 {
1262 if (m_orient == wxHORIZONTAL)
1263 {
1264 delta = (m_size.x - m_fixedWidth) / m_stretchable;
1265 extra = (m_size.x - m_fixedWidth) % m_stretchable;
3ca6a5f0
BP
1266 }
1267 else
1268 {
61d514bb
RR
1269 delta = (m_size.y - m_fixedHeight) / m_stretchable;
1270 extra = (m_size.y - m_fixedHeight) % m_stretchable;
3ca6a5f0 1271 }
61d514bb 1272 }
0c0d686f 1273
61d514bb 1274 wxPoint pt( m_position );
0c0d686f 1275
12a3f227 1276 wxSizerItemList::Node *node = m_children.GetFirst();
61d514bb
RR
1277 while (node)
1278 {
12a3f227
RL
1279 wxSizerItem *item = node->GetData();
1280
2b5f62a0 1281 if (item->IsShown())
3ca6a5f0 1282 {
2b5f62a0 1283 int weight = 1;
12a3f227
RL
1284 if (item->GetProportion())
1285 weight = item->GetProportion();
3ca6a5f0 1286
2b5f62a0 1287 wxSize size( item->CalcMin() );
3ca6a5f0 1288
2b5f62a0 1289 if (m_orient == wxVERTICAL)
3ca6a5f0 1290 {
2b5f62a0 1291 wxCoord height = size.y;
12a3f227 1292 if (item->GetProportion())
2b5f62a0
VZ
1293 {
1294 height = (delta * weight) + extra;
1295 extra = 0; // only the first item will get the remainder as extra size
1296 }
1297
1298 wxPoint child_pos( pt );
1299 wxSize child_size( wxSize( size.x, height) );
1300
1301 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1302 child_size.x = m_size.x;
1303 else if (item->GetFlag() & wxALIGN_RIGHT)
1304 child_pos.x += m_size.x - size.x;
1305 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1306 // XXX wxCENTER is added for backward compatibility;
1307 // wxALIGN_CENTER should be used in new code
1308 child_pos.x += (m_size.x - size.x) / 2;
1309
1310 item->SetDimension( child_pos, child_size );
1311
1312 pt.y += height;
1313 }
1314 else
1315 {
1316 wxCoord width = size.x;
12a3f227 1317 if (item->GetProportion())
2b5f62a0
VZ
1318 {
1319 width = (delta * weight) + extra;
1320 extra = 0; // only the first item will get the remainder as extra size
1321 }
1322
1323 wxPoint child_pos( pt );
1324 wxSize child_size( wxSize(width, size.y) );
1325
1326 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1327 child_size.y = m_size.y;
1328 else if (item->GetFlag() & wxALIGN_BOTTOM)
1329 child_pos.y += m_size.y - size.y;
1330 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1331 // XXX wxCENTER is added for backward compatibility;
1332 // wxALIGN_CENTER should be used in new code
1333 child_pos.y += (m_size.y - size.y) / 2;
1334
1335 item->SetDimension( child_pos, child_size );
1336
1337 pt.x += width;
3ca6a5f0 1338 }
3ca6a5f0
BP
1339 }
1340
12a3f227 1341 node = node->GetNext();
61d514bb
RR
1342 }
1343}
1344
92afa2b1 1345wxSize wxBoxSizer::CalcMin()
61d514bb
RR
1346{
1347 if (m_children.GetCount() == 0)
c7a9fa36 1348 return wxSize(10,10);
0c0d686f 1349
61d514bb
RR
1350 m_stretchable = 0;
1351 m_minWidth = 0;
1352 m_minHeight = 0;
1353 m_fixedWidth = 0;
1354 m_fixedHeight = 0;
0c0d686f 1355
f98de448 1356 // Find how long each stretch unit needs to be
12a3f227
RL
1357 int stretchSize = 1;
1358 wxSizerItemList::Node *node = m_children.GetFirst();
1359
61d514bb 1360 while (node)
f98de448 1361 {
12a3f227
RL
1362 wxSizerItem *item = node->GetData();
1363
1364 if (item->IsShown() && item->GetProportion() != 0)
f98de448 1365 {
12a3f227 1366 int stretch = item->GetProportion();
f98de448
RD
1367 wxSize size( item->CalcMin() );
1368 int sizePerStretch;
1369 // Integer division rounded up is (a + b - 1) / b
1370 if (m_orient == wxHORIZONTAL)
1371 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1372 else
1373 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1374 if (sizePerStretch > stretchSize)
1375 stretchSize = sizePerStretch;
1376 }
12a3f227 1377 node = node->GetNext();
f98de448 1378 }
12a3f227 1379
4f469fb5
RR
1380 // Calculate overall minimum size
1381 node = m_children.GetFirst();
f98de448 1382 while (node)
61d514bb 1383 {
12a3f227
RL
1384 wxSizerItem *item = node->GetData();
1385
2b5f62a0 1386 if (item->IsShown())
f98de448 1387 {
12a3f227 1388 m_stretchable += item->GetProportion();
3ca6a5f0 1389
2b5f62a0 1390 wxSize size( item->CalcMin() );
12a3f227 1391 if (item->GetProportion() != 0)
2b5f62a0
VZ
1392 {
1393 if (m_orient == wxHORIZONTAL)
12a3f227 1394 size.x = stretchSize * item->GetProportion();
2b5f62a0 1395 else
12a3f227 1396 size.y = stretchSize * item->GetProportion();
2b5f62a0 1397 }
3ca6a5f0 1398
2b5f62a0 1399 if (m_orient == wxHORIZONTAL)
3ca6a5f0 1400 {
2b5f62a0
VZ
1401 m_minWidth += size.x;
1402 m_minHeight = wxMax( m_minHeight, size.y );
3ca6a5f0
BP
1403 }
1404 else
33ac7e6f 1405 {
2b5f62a0
VZ
1406 m_minHeight += size.y;
1407 m_minWidth = wxMax( m_minWidth, size.x );
3ca6a5f0 1408 }
3ca6a5f0 1409
12a3f227 1410 if (item->GetProportion() == 0)
2b5f62a0
VZ
1411 {
1412 if (m_orient == wxVERTICAL)
1413 {
1414 m_fixedHeight += size.y;
1415 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1416 }
1417 else
1418 {
1419 m_fixedWidth += size.x;
1420 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1421 }
1422 }
1423 }
12a3f227 1424 node = node->GetNext();
61d514bb 1425 }
0c0d686f 1426
61d514bb
RR
1427 return wxSize( m_minWidth, m_minHeight );
1428}
27ea1d8a
RR
1429
1430//---------------------------------------------------------------------------
1431// wxStaticBoxSizer
1432//---------------------------------------------------------------------------
1433
1e6feb95
VZ
1434#if wxUSE_STATBOX
1435
27ea1d8a 1436wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
12a3f227
RL
1437 : wxBoxSizer( orient )
1438 , m_staticBox( box )
27ea1d8a 1439{
223d09f6 1440 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
27ea1d8a 1441}
0c0d686f 1442
12a3f227
RL
1443static void GetStaticBoxBorders( wxStaticBox *box,
1444 int *borderTop,
1445 int *borderOther)
84028727
VZ
1446{
1447 // this has to be done platform by platform as there is no way to
1448 // guess the thickness of a wxStaticBox border
1449#ifdef __WXGTK__
1450 if ( box->GetLabel().IsEmpty() )
1451 *borderTop = 5;
1452 else
1453#endif // __WXGTK__
f2b99f63
JS
1454 *borderTop = box->GetCharHeight();
1455
84028727
VZ
1456 *borderOther = 5;
1457}
1458
27ea1d8a
RR
1459void wxStaticBoxSizer::RecalcSizes()
1460{
84028727
VZ
1461 int top_border, other_border;
1462 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
1463
1464 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 1465
27ea1d8a
RR
1466 wxPoint old_pos( m_position );
1467 m_position.x += other_border;
1468 m_position.y += top_border;
1469 wxSize old_size( m_size );
1470 m_size.x -= 2*other_border;
1471 m_size.y -= top_border + other_border;
0c0d686f 1472
27ea1d8a 1473 wxBoxSizer::RecalcSizes();
0c0d686f 1474
27ea1d8a
RR
1475 m_position = old_pos;
1476 m_size = old_size;
1477}
1478
1479wxSize wxStaticBoxSizer::CalcMin()
1480{
84028727
VZ
1481 int top_border, other_border;
1482 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 1483
27ea1d8a 1484 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 1485 ret.x += 2*other_border;
27ea1d8a 1486 ret.y += other_border + top_border;
0c0d686f 1487
27ea1d8a
RR
1488 return ret;
1489}
83edc0a5 1490
1e6feb95
VZ
1491#endif // wxUSE_STATBOX
1492
83edc0a5
RR
1493//---------------------------------------------------------------------------
1494// wxNotebookSizer
1495//---------------------------------------------------------------------------
1496
60be2f47
VS
1497#if wxUSE_NOTEBOOK
1498
83edc0a5 1499wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
12a3f227 1500 : m_notebook( nb )
83edc0a5
RR
1501{
1502 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
83edc0a5
RR
1503}
1504
1505void wxNotebookSizer::RecalcSizes()
1506{
1507 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1508}
1509
1510wxSize wxNotebookSizer::CalcMin()
1511{
1e6feb95
VZ
1512 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1513
1514 sizeBorder.x += 5;
1515 sizeBorder.y += 5;
3ca6a5f0 1516
83edc0a5 1517 if (m_notebook->GetChildren().GetCount() == 0)
1e6feb95
VZ
1518 {
1519 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1520 }
83edc0a5
RR
1521
1522 int maxX = 0;
1523 int maxY = 0;
1524
1525 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1526 while (node)
1527 {
1528 wxWindow *item = node->GetData();
3ca6a5f0
BP
1529 wxSizer *itemsizer = item->GetSizer();
1530
1531 if (itemsizer)
1532 {
83edc0a5 1533 wxSize subsize( itemsizer->CalcMin() );
83edc0a5 1534
1e6feb95
VZ
1535 if (subsize.x > maxX)
1536 maxX = subsize.x;
1537 if (subsize.y > maxY)
1538 maxY = subsize.y;
3ca6a5f0
BP
1539 }
1540
1541 node = node->GetNext();
83edc0a5
RR
1542 }
1543
1e6feb95 1544 return wxSize( maxX, maxY ) + sizeBorder;
83edc0a5
RR
1545}
1546
60be2f47 1547#endif // wxUSE_NOTEBOOK
34c3ffca
RL
1548
1549// vi:sts=4:sw=4:et