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