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