]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
added wxUmaskChanger class and wxCHANGE_UMASK macro and use them instead of duplicati...
[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
8b2bac62 763bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
2b5f62a0 764{
12a3f227
RL
765 wxASSERT_MSG( window, _T("Show for NULL window") );
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 {
12a3f227 774 item->Show( show );
8b2bac62
WS
775
776 return true;
2b5f62a0 777 }
8b2bac62
WS
778 else if (recursive && item->IsSizer())
779 {
780 if (item->GetSizer()->Show(window, show, recursive))
781 return true;
782 }
783
12a3f227 784 node = node->GetNext();
2b5f62a0 785 }
8b2bac62
WS
786
787 return false;
2b5f62a0
VZ
788}
789
8b2bac62 790bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
2b5f62a0 791{
12a3f227
RL
792 wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
793
222ed1d6 794 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
795 while (node)
796 {
12a3f227 797 wxSizerItem *item = node->GetData();
2b5f62a0 798
12a3f227 799 if (item->GetSizer() == sizer)
2b5f62a0 800 {
12a3f227 801 item->Show( show );
8b2bac62
WS
802
803 return true;
2b5f62a0 804 }
8b2bac62
WS
805 else if (recursive && item->IsSizer())
806 {
807 if (item->GetSizer()->Show(sizer, show, recursive))
808 return true;
809 }
810
12a3f227 811 node = node->GetNext();
2b5f62a0 812 }
8b2bac62
WS
813
814 return false;
2b5f62a0
VZ
815}
816
8b2bac62 817bool wxSizer::Show( size_t index, bool show)
2b5f62a0 818{
8b2bac62
WS
819 wxCHECK_MSG( index < m_children.GetCount(),
820 false,
12a3f227 821 _T("Show index is out of range") );
2b5f62a0 822
12a3f227 823 m_children.Item( index )->GetData()->Show( show );
8b2bac62
WS
824
825 return true;
12a3f227 826}
2b5f62a0 827
12a3f227
RL
828void wxSizer::ShowItems( bool show )
829{
222ed1d6 830 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
831 while (node)
832 {
833 node->GetData()->Show( show );
834 node = node->GetNext();
2b5f62a0
VZ
835 }
836}
837
9cbee2ce 838bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 839{
222ed1d6 840 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
841 while (node)
842 {
12a3f227 843 wxSizerItem *item = node->GetData();
dc259b79 844
12a3f227 845 if (item->GetWindow() == window)
2b5f62a0
VZ
846 {
847 return item->IsShown();
848 }
12a3f227 849 node = node->GetNext();
2b5f62a0
VZ
850 }
851
12a3f227
RL
852 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
853
e0d8fb45 854 return false;
2b5f62a0
VZ
855}
856
9cbee2ce 857bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 858{
222ed1d6 859 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
860 while (node)
861 {
12a3f227 862 wxSizerItem *item = node->GetData();
2b5f62a0 863
12a3f227 864 if (item->GetSizer() == sizer)
2b5f62a0
VZ
865 {
866 return item->IsShown();
867 }
12a3f227 868 node = node->GetNext();
2b5f62a0
VZ
869 }
870
12a3f227
RL
871 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
872
e0d8fb45 873 return false;
2b5f62a0
VZ
874}
875
9cbee2ce 876bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
877{
878 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 879 false,
12a3f227
RL
880 _T("IsShown index is out of range") );
881
882 return m_children.Item( index )->GetData()->IsShown();
883}
884
885
f6bcfd97
BP
886//---------------------------------------------------------------------------
887// wxGridSizer
888//---------------------------------------------------------------------------
889
890wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
12a3f227
RL
891 : m_rows( rows )
892 , m_cols( cols )
893 , m_vgap( vgap )
894 , m_hgap( hgap )
f6bcfd97 895{
02319c24
RD
896 if (m_rows == 0 && m_cols == 0)
897 m_rows = 1;
f6bcfd97
BP
898}
899
900wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
12a3f227
RL
901 : m_rows( 0 )
902 , m_cols( cols )
903 , m_vgap( vgap )
904 , m_hgap( hgap )
f6bcfd97 905{
02319c24
RD
906 if (m_rows == 0 && m_cols == 0)
907 m_rows = 1;
f6bcfd97
BP
908}
909
0ca5105b 910int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 911{
f6bcfd97 912 int nitems = m_children.GetCount();
2b5f62a0 913 if ( nitems)
0ca5105b
VZ
914 {
915 if ( m_cols )
916 {
917 ncols = m_cols;
918 nrows = (nitems + m_cols - 1) / m_cols;
919 }
920 else if ( m_rows )
921 {
922 ncols = (nitems + m_rows - 1) / m_rows;
923 nrows = m_rows;
924 }
925 else // 0 columns, 0 rows?
926 {
927 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 928
0ca5105b
VZ
929 nrows = ncols = 0;
930 }
931 }
932
933 return nitems;
934}
935
936void wxGridSizer::RecalcSizes()
937{
938 int nitems, nrows, ncols;
939 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
940 return;
f6bcfd97
BP
941
942 wxSize sz( GetSize() );
943 wxPoint pt( GetPosition() );
3ca6a5f0
BP
944
945 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
946 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
947
948 int x = pt.x;
949 for (int c = 0; c < ncols; c++)
950 {
951 int y = pt.y;
952 for (int r = 0; r < nrows; r++)
953 {
954 int i = r * ncols + c;
955 if (i < nitems)
956 {
222ed1d6 957 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
958
959 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 960
12a3f227 961 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
962 }
963 y = y + h + m_vgap;
964 }
965 x = x + w + m_hgap;
966 }
967}
968
969wxSize wxGridSizer::CalcMin()
970{
196be0f1
JS
971 int nrows, ncols;
972 if ( CalcRowsCols(nrows, ncols) == 0 )
0ca5105b 973 return wxSize(10, 10);
f6bcfd97 974
4f469fb5 975 // Find the max width and height for any component
f6bcfd97
BP
976 int w = 0;
977 int h = 0;
3ca6a5f0 978
222ed1d6 979 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
980 while (node)
981 {
12a3f227
RL
982 wxSizerItem *item = node->GetData();
983 wxSize sz( item->CalcMin() );
984
f6bcfd97
BP
985 w = wxMax( w, sz.x );
986 h = wxMax( h, sz.y );
3ca6a5f0 987
12a3f227 988 node = node->GetNext();
f6bcfd97 989 }
3ca6a5f0 990
12a3f227
RL
991 return wxSize( ncols * w + (ncols-1) * m_hgap,
992 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
993}
994
995void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
996{
997 wxPoint pt( x,y );
8b2bac62 998 wxSize sz( item->GetMinSizeWithBorder() );
f6bcfd97
BP
999 int flag = item->GetFlag();
1000
1001 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1002 {
1003 sz = wxSize(w, h);
1004 }
1005 else
1006 {
1007 if (flag & wxALIGN_CENTER_HORIZONTAL)
1008 {
559b747d 1009 pt.x = x + (w - sz.x) / 2;
f6bcfd97
BP
1010 }
1011 else if (flag & wxALIGN_RIGHT)
1012 {
559b747d 1013 pt.x = x + (w - sz.x);
f6bcfd97 1014 }
3ca6a5f0 1015
f6bcfd97
BP
1016 if (flag & wxALIGN_CENTER_VERTICAL)
1017 {
559b747d 1018 pt.y = y + (h - sz.y) / 2;
f6bcfd97
BP
1019 }
1020 else if (flag & wxALIGN_BOTTOM)
1021 {
559b747d 1022 pt.y = y + (h - sz.y);
f6bcfd97
BP
1023 }
1024 }
3ca6a5f0 1025
f6bcfd97
BP
1026 item->SetDimension(pt, sz);
1027}
1028
1029//---------------------------------------------------------------------------
1030// wxFlexGridSizer
1031//---------------------------------------------------------------------------
1032
1033wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1034 : wxGridSizer( rows, cols, vgap, hgap ),
1035 m_flexDirection(wxBOTH),
1036 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1037{
f6bcfd97
BP
1038}
1039
1040wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1041 : wxGridSizer( cols, vgap, hgap ),
1042 m_flexDirection(wxBOTH),
1043 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1044{
f6bcfd97 1045}
3ca6a5f0 1046
f6bcfd97
BP
1047wxFlexGridSizer::~wxFlexGridSizer()
1048{
f6bcfd97
BP
1049}
1050
1051void wxFlexGridSizer::RecalcSizes()
1052{
0ca5105b
VZ
1053 int nitems, nrows, ncols;
1054 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
f6bcfd97
BP
1055 return;
1056
20b35a69 1057 wxPoint pt( GetPosition() );
f6bcfd97 1058 wxSize sz( GetSize() );
5d76f462 1059
ba763a45 1060 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
3ca6a5f0 1061
f6bcfd97
BP
1062 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1063
1064 int x = pt.x;
1065 for (int c = 0; c < ncols; c++)
1066 {
1067 int y = pt.y;
1068 for (int r = 0; r < nrows; r++)
1069 {
1070 int i = r * ncols + c;
1071 if (i < nitems)
1072 {
222ed1d6 1073 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1074
1075 wxASSERT_MSG( node, _T("Failed to find node") );
3ca6a5f0 1076
f6bcfd97
BP
1077 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1078 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
3ca6a5f0 1079
12a3f227 1080 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1081 }
1082 y = y + m_rowHeights[r] + m_vgap;
1083 }
1084 x = x + m_colWidths[c] + m_hgap;
1085 }
1086}
1087
1088wxSize wxFlexGridSizer::CalcMin()
1089{
150c8d89
RL
1090 int nrows,
1091 ncols;
1092 size_t i, s;
1093
55f9f0cb 1094 // Number of rows/columns can change as items are added or removed.
5d76f462
VZ
1095 if ( !CalcRowsCols(nrows, ncols) )
1096 return wxSize(10, 10);
f6bcfd97 1097
5d76f462
VZ
1098 m_rowHeights.SetCount(nrows);
1099 m_colWidths.SetCount(ncols);
3ca6a5f0 1100
395a82b1
VZ
1101 // We have to recalcuate the sizes in case the item minimum size has
1102 // changed since the previous layout, or the item has been hidden using
1103 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1104 // dimension of the row/column will be -1, indicating that the column
1105 // itself is hidden.
55f9f0cb
VZ
1106 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1107 m_rowHeights[ i ] = -1;
1108 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1109 m_colWidths[ i ] = -1;
1110
222ed1d6 1111 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227 1112
150c8d89 1113 i = 0;
f6bcfd97
BP
1114 while (node)
1115 {
12a3f227 1116 wxSizerItem *item = node->GetData();
55f9f0cb
VZ
1117 if ( item->IsShown() )
1118 {
1119 wxSize sz( item->CalcMin() );
1120 int row = i / ncols;
1121 int col = i % ncols;
12a3f227 1122
55f9f0cb
VZ
1123 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1124 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1125 }
3ca6a5f0 1126
12a3f227 1127 node = node->GetNext();
f6bcfd97
BP
1128 i++;
1129 }
3ca6a5f0 1130
20b35a69 1131 AdjustForFlexDirection();
8b2bac62 1132
20b35a69
RD
1133 // Sum total minimum size, including gaps between rows/columns.
1134 // -1 is used as a magic number meaning empty column.
1135 int width = 0;
1136 for (int col = 0; col < ncols; col++)
1137 if ( m_colWidths[ col ] != -1 )
1138 width += m_colWidths[ col ] + ( col == ncols-1 ? 0 : m_hgap );
1139
1140 int height = 0;
1141 for (int row = 0; row < nrows; row++)
1142 if ( m_rowHeights[ row ] != -1 )
1143 height += m_rowHeights[ row ] + ( row == nrows-1 ? 0 : m_vgap );
1144
ba763a45
RD
1145 m_calculatedMinSize = wxSize( width, height );
1146 return m_calculatedMinSize;
20b35a69
RD
1147}
1148
1149void wxFlexGridSizer::AdjustForFlexDirection()
1150{
1151 // the logic in CalcMin works when we resize flexibly in both directions
1152 // but maybe this is not the case
5d76f462
VZ
1153 if ( m_flexDirection != wxBOTH )
1154 {
1155 // select the array corresponding to the direction in which we do *not*
1156 // resize flexibly
1157 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1158 : m_rowHeights;
1159
1160 const int count = array.GetCount();
1161
1162 // find the largest value in this array
55f9f0cb 1163 int n, largest = 0;
5d76f462
VZ
1164 for ( n = 0; n < count; ++n )
1165 {
1166 if ( array[n] > largest )
1167 largest = array[n];
1168 }
1169
1170 // and now fill it with the largest value
1171 for ( n = 0; n < count; ++n )
1172 {
1173 array[n] = largest;
1174 }
1175 }
8b2bac62 1176}
5d76f462 1177
3ca6a5f0 1178
20b35a69
RD
1179void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1180 int nrows, int ncols)
1181{
1182 // what to do with the rows? by default, resize them proportionally
1183 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1184 {
1185 int sum_proportions = 0;
1186 int growable_space = 0;
1187 int num = 0;
1188 size_t idx;
1189 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1190 {
1191 // Since the number of rows/columns can change as items are
1192 // inserted/deleted, we need to verify at runtime that the
1193 // requested growable rows/columns are still valid.
1194 if (m_growableRows[idx] >= nrows)
1195 continue;
8b2bac62 1196
20b35a69
RD
1197 // If all items in a row/column are hidden, that row/column will
1198 // have a dimension of -1. This causes the row/column to be
1199 // hidden completely.
1200 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1201 continue;
1202 sum_proportions += m_growableRowsProportions[idx];
1203 growable_space += m_rowHeights[ m_growableRows[idx] ];
1204 num++;
1205 }
3ca6a5f0 1206
20b35a69
RD
1207 if (num > 0)
1208 {
1209 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1210 {
1211 if (m_growableRows[idx] >= nrows )
1212 continue;
1213 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1214 m_rowHeights[ m_growableRows[idx] ] = 0;
1215 else
1216 {
1217 int delta = (sz.y - minsz.y);
1218 if (sum_proportions == 0)
1219 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1220 else
1221 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1222 m_rowHeights[ m_growableRows[idx] ] = delta;
1223 }
1224 }
1225 }
1226 }
1227 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1228 {
1229 // rounding problem?
1230 for ( int row = 0; row < nrows; ++row )
1231 m_rowHeights[ row ] = sz.y / nrows;
1232 }
1233
1234 // the same logic as above but for the columns
1235 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1236 {
1237 int sum_proportions = 0;
1238 int growable_space = 0;
1239 int num = 0;
1240 size_t idx;
1241 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1242 {
1243 // Since the number of rows/columns can change as items are
1244 // inserted/deleted, we need to verify at runtime that the
1245 // requested growable rows/columns are still valid.
1246 if (m_growableCols[idx] >= ncols)
1247 continue;
8b2bac62 1248
20b35a69
RD
1249 // If all items in a row/column are hidden, that row/column will
1250 // have a dimension of -1. This causes the column to be hidden
1251 // completely.
1252 if (m_colWidths[ m_growableCols[idx] ] == -1)
1253 continue;
1254 sum_proportions += m_growableColsProportions[idx];
1255 growable_space += m_colWidths[ m_growableCols[idx] ];
1256 num++;
1257 }
1258
1259 if (num > 0)
1260 {
1261 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1262 {
1263 if (m_growableCols[idx] >= ncols )
1264 continue;
1265 if (m_colWidths[ m_growableCols[idx] ] == -1)
1266 m_colWidths[ m_growableCols[idx] ] = 0;
1267 else
1268 {
1269 int delta = (sz.x - minsz.x);
1270 if (sum_proportions == 0)
1271 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1272 else
1273 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1274 m_colWidths[ m_growableCols[idx] ] = delta;
1275 }
1276 }
1277 }
1278 }
1279 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1280 {
1281 for ( int col=0; col < ncols; ++col )
1282 m_colWidths[ col ] = sz.x / ncols;
1283 }
f6bcfd97
BP
1284}
1285
20b35a69 1286
e8800dcf 1287void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1288{
1289 m_growableRows.Add( idx );
e8800dcf 1290 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1291}
1292
8d2474f4 1293void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
f6bcfd97 1294{
8d2474f4 1295 m_growableRows.Remove( idx );
f6bcfd97
BP
1296}
1297
e8800dcf 1298void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1299{
1300 m_growableCols.Add( idx );
e8800dcf 1301 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1302}
1303
8d2474f4 1304void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
f6bcfd97 1305{
8d2474f4 1306 m_growableCols.Remove( idx );
f6bcfd97
BP
1307}
1308
c62ac5b6 1309//---------------------------------------------------------------------------
92afa2b1 1310// wxBoxSizer
61d514bb
RR
1311//---------------------------------------------------------------------------
1312
92afa2b1 1313wxBoxSizer::wxBoxSizer( int orient )
12a3f227 1314 : m_orient( orient )
61d514bb 1315{
61d514bb
RR
1316}
1317
92afa2b1 1318void wxBoxSizer::RecalcSizes()
61d514bb
RR
1319{
1320 if (m_children.GetCount() == 0)
61d514bb 1321 return;
0c0d686f 1322
61d514bb 1323 int delta = 0;
61d514bb
RR
1324 if (m_stretchable)
1325 {
1326 if (m_orient == wxHORIZONTAL)
85e5cfc9 1327 delta = m_size.x - m_fixedWidth;
3ca6a5f0 1328 else
85e5cfc9 1329 delta = m_size.y - m_fixedHeight;
61d514bb 1330 }
0c0d686f 1331
61d514bb 1332 wxPoint pt( m_position );
0c0d686f 1333
222ed1d6 1334 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
61d514bb
RR
1335 while (node)
1336 {
12a3f227
RL
1337 wxSizerItem *item = node->GetData();
1338
2b5f62a0 1339 if (item->IsShown())
3ca6a5f0 1340 {
ba763a45 1341 wxSize size( item->GetMinSizeWithBorder() );
3ca6a5f0 1342
2b5f62a0 1343 if (m_orient == wxVERTICAL)
3ca6a5f0 1344 {
2b5f62a0 1345 wxCoord height = size.y;
12a3f227 1346 if (item->GetProportion())
2b5f62a0 1347 {
85e5cfc9
VZ
1348 // Because of at least one visible item has non-zero
1349 // proportion then m_stretchable is not zero
1350 height = (delta * item->GetProportion()) / m_stretchable;
2b5f62a0
VZ
1351 }
1352
1353 wxPoint child_pos( pt );
1354 wxSize child_size( wxSize( size.x, height) );
1355
1356 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1357 child_size.x = m_size.x;
1358 else if (item->GetFlag() & wxALIGN_RIGHT)
1359 child_pos.x += m_size.x - size.x;
1360 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1361 // XXX wxCENTER is added for backward compatibility;
1362 // wxALIGN_CENTER should be used in new code
1363 child_pos.x += (m_size.x - size.x) / 2;
1364
1365 item->SetDimension( child_pos, child_size );
1366
1367 pt.y += height;
1368 }
1369 else
1370 {
1371 wxCoord width = size.x;
12a3f227 1372 if (item->GetProportion())
2b5f62a0 1373 {
85e5cfc9
VZ
1374 // Because of at least one visible item has non-zero
1375 // proportion then m_stretchable is not zero
1376 width = (delta * item->GetProportion()) / m_stretchable;
2b5f62a0
VZ
1377 }
1378
1379 wxPoint child_pos( pt );
1380 wxSize child_size( wxSize(width, size.y) );
1381
1382 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1383 child_size.y = m_size.y;
1384 else if (item->GetFlag() & wxALIGN_BOTTOM)
1385 child_pos.y += m_size.y - size.y;
1386 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1387 // XXX wxCENTER is added for backward compatibility;
1388 // wxALIGN_CENTER should be used in new code
1389 child_pos.y += (m_size.y - size.y) / 2;
1390
1391 item->SetDimension( child_pos, child_size );
1392
1393 pt.x += width;
3ca6a5f0 1394 }
3ca6a5f0
BP
1395 }
1396
12a3f227 1397 node = node->GetNext();
61d514bb
RR
1398 }
1399}
1400
92afa2b1 1401wxSize wxBoxSizer::CalcMin()
61d514bb
RR
1402{
1403 if (m_children.GetCount() == 0)
c7a9fa36 1404 return wxSize(10,10);
0c0d686f 1405
61d514bb
RR
1406 m_stretchable = 0;
1407 m_minWidth = 0;
1408 m_minHeight = 0;
1409 m_fixedWidth = 0;
1410 m_fixedHeight = 0;
0c0d686f 1411
ba763a45 1412 // precalc item minsizes and count proportions
222ed1d6 1413 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
85e5cfc9
VZ
1414 while (node)
1415 {
1416 wxSizerItem *item = node->GetData();
12a3f227 1417
ba763a45
RD
1418 if (item->IsShown())
1419 item->CalcMin(); // result is stored in the item
8b2bac62 1420
85e5cfc9
VZ
1421 if (item->IsShown() && item->GetProportion() != 0)
1422 m_stretchable += item->GetProportion();
1423
1424 node = node->GetNext();
1425 }
1426
1427 // Total minimum size (width or height) of sizer
1428 int maxMinSize = 0;
1429
1430 node = m_children.GetFirst();
61d514bb 1431 while (node)
f98de448 1432 {
85e5cfc9 1433 wxSizerItem *item = node->GetData();
12a3f227
RL
1434
1435 if (item->IsShown() && item->GetProportion() != 0)
f98de448 1436 {
12a3f227 1437 int stretch = item->GetProportion();
ba763a45 1438 wxSize size( item->GetMinSizeWithBorder() );
85e5cfc9 1439 int minSize;
8b2bac62 1440
f98de448 1441 // Integer division rounded up is (a + b - 1) / b
85e5cfc9
VZ
1442 // Round up needed in order to guarantee that all
1443 // all items will have size not less then their min size
f98de448 1444 if (m_orient == wxHORIZONTAL)
85e5cfc9 1445 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
f98de448 1446 else
85e5cfc9 1447 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
8b2bac62 1448
85e5cfc9
VZ
1449 if (minSize > maxMinSize)
1450 maxMinSize = minSize;
f98de448 1451 }
12a3f227 1452 node = node->GetNext();
f98de448 1453 }
12a3f227 1454
4f469fb5
RR
1455 // Calculate overall minimum size
1456 node = m_children.GetFirst();
f98de448 1457 while (node)
61d514bb 1458 {
85e5cfc9 1459 wxSizerItem *item = node->GetData();
12a3f227 1460
2b5f62a0 1461 if (item->IsShown())
f98de448 1462 {
ba763a45 1463 wxSize size( item->GetMinSizeWithBorder() );
12a3f227 1464 if (item->GetProportion() != 0)
2b5f62a0
VZ
1465 {
1466 if (m_orient == wxHORIZONTAL)
85e5cfc9 1467 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
2b5f62a0 1468 else
85e5cfc9 1469 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
3ca6a5f0
BP
1470 }
1471 else
2b5f62a0
VZ
1472 {
1473 if (m_orient == wxVERTICAL)
1474 {
1475 m_fixedHeight += size.y;
1476 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1477 }
1478 else
1479 {
1480 m_fixedWidth += size.x;
1481 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1482 }
1483 }
85e5cfc9
VZ
1484
1485 if (m_orient == wxHORIZONTAL)
1486 {
1487 m_minWidth += size.x;
1488 m_minHeight = wxMax( m_minHeight, size.y );
1489 }
1490 else
1491 {
1492 m_minHeight += size.y;
1493 m_minWidth = wxMax( m_minWidth, size.x );
1494 }
2b5f62a0 1495 }
12a3f227 1496 node = node->GetNext();
61d514bb 1497 }
0c0d686f 1498
61d514bb
RR
1499 return wxSize( m_minWidth, m_minHeight );
1500}
27ea1d8a
RR
1501
1502//---------------------------------------------------------------------------
1503// wxStaticBoxSizer
1504//---------------------------------------------------------------------------
1505
1e6feb95
VZ
1506#if wxUSE_STATBOX
1507
27ea1d8a 1508wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
12a3f227
RL
1509 : wxBoxSizer( orient )
1510 , m_staticBox( box )
27ea1d8a 1511{
223d09f6 1512 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
27ea1d8a 1513}
0c0d686f 1514
12a3f227
RL
1515static void GetStaticBoxBorders( wxStaticBox *box,
1516 int *borderTop,
1517 int *borderOther)
84028727
VZ
1518{
1519 // this has to be done platform by platform as there is no way to
1520 // guess the thickness of a wxStaticBox border
ec4e4a14
DE
1521#ifdef __WXCOCOA__
1522 box->GetBordersForSizer(borderTop,borderOther);
67021102
DS
1523#elif defined(__WXMAC__)
1524
1525 static int extraTop = -1; // Uninitted
1526 static int other = 5;
1527
1528 if ( extraTop == -1 )
1529 {
67021102
DS
1530 // The minimal border used for the top. Later on the staticbox'
1531 // font height is added to this.
1532 extraTop = 0;
1533
78ca5669 1534 if ( UMAGetSystemVersion() >= 0x1030 /*Panther*/ )
67021102
DS
1535 {
1536 // As indicated by the HIG, Panther needs an extra border of 11
1537 // pixels (otherwise overlapping occurs at the top). The "other"
1538 // border has to be 11.
1539 extraTop = 11;
8b2bac62 1540 other = 11;
67021102
DS
1541 }
1542
1543 }
1544
1545 *borderTop = extraTop + box->GetCharHeight();
1546 *borderOther = other;
1547
1548#else
84028727
VZ
1549#ifdef __WXGTK__
1550 if ( box->GetLabel().IsEmpty() )
1551 *borderTop = 5;
1552 else
1553#endif // __WXGTK__
f2b99f63
JS
1554 *borderTop = box->GetCharHeight();
1555
84028727 1556 *borderOther = 5;
ec4e4a14 1557#endif // __WXCOCOA__
84028727
VZ
1558}
1559
27ea1d8a
RR
1560void wxStaticBoxSizer::RecalcSizes()
1561{
84028727
VZ
1562 int top_border, other_border;
1563 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
1564
1565 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 1566
27ea1d8a
RR
1567 wxPoint old_pos( m_position );
1568 m_position.x += other_border;
1569 m_position.y += top_border;
1570 wxSize old_size( m_size );
1571 m_size.x -= 2*other_border;
1572 m_size.y -= top_border + other_border;
0c0d686f 1573
27ea1d8a 1574 wxBoxSizer::RecalcSizes();
0c0d686f 1575
27ea1d8a
RR
1576 m_position = old_pos;
1577 m_size = old_size;
1578}
1579
1580wxSize wxStaticBoxSizer::CalcMin()
1581{
84028727
VZ
1582 int top_border, other_border;
1583 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 1584
27ea1d8a 1585 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 1586 ret.x += 2*other_border;
27ea1d8a 1587 ret.y += other_border + top_border;
0c0d686f 1588
27ea1d8a
RR
1589 return ret;
1590}
83edc0a5 1591
eb2a7883
VZ
1592void wxStaticBoxSizer::ShowItems( bool show )
1593{
1594 m_staticBox->Show( show );
1595 wxBoxSizer::ShowItems( show );
1596}
1597
1e6feb95
VZ
1598#endif // wxUSE_STATBOX
1599
adbf2d73
VS
1600
1601#if WXWIN_COMPATIBILITY_2_4
1602
ade4eb65 1603// ----------------------------------------------------------------------------
83edc0a5 1604// wxNotebookSizer
ade4eb65 1605// ----------------------------------------------------------------------------
83edc0a5 1606
adbf2d73
VS
1607#if wxUSE_BOOKCTRL
1608IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1609#if wxUSE_NOTEBOOK
1610IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1611#endif // wxUSE_NOTEBOOK
1612#endif // wxUSE_BOOKCTRL
1613
ade4eb65 1614#if wxUSE_BOOKCTRL
60be2f47 1615
ade4eb65
VZ
1616wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl *bookctrl)
1617 : m_bookctrl(bookctrl)
83edc0a5 1618{
ade4eb65 1619 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
83edc0a5
RR
1620}
1621
ade4eb65 1622void wxBookCtrlSizer::RecalcSizes()
83edc0a5 1623{
ade4eb65 1624 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
83edc0a5
RR
1625}
1626
ade4eb65 1627wxSize wxBookCtrlSizer::CalcMin()
83edc0a5 1628{
ade4eb65 1629 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
1e6feb95
VZ
1630
1631 sizeBorder.x += 5;
1632 sizeBorder.y += 5;
3ca6a5f0 1633
ade4eb65 1634 if ( m_bookctrl->GetPageCount() == 0 )
1e6feb95
VZ
1635 {
1636 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1637 }
83edc0a5
RR
1638
1639 int maxX = 0;
1640 int maxY = 0;
1641
ade4eb65
VZ
1642 wxWindowList::compatibility_iterator
1643 node = m_bookctrl->GetChildren().GetFirst();
83edc0a5
RR
1644 while (node)
1645 {
1646 wxWindow *item = node->GetData();
3ca6a5f0
BP
1647 wxSizer *itemsizer = item->GetSizer();
1648
1649 if (itemsizer)
1650 {
83edc0a5 1651 wxSize subsize( itemsizer->CalcMin() );
83edc0a5 1652
1e6feb95
VZ
1653 if (subsize.x > maxX)
1654 maxX = subsize.x;
1655 if (subsize.y > maxY)
1656 maxY = subsize.y;
3ca6a5f0
BP
1657 }
1658
1659 node = node->GetNext();
83edc0a5
RR
1660 }
1661
1e6feb95 1662 return wxSize( maxX, maxY ) + sizeBorder;
83edc0a5
RR
1663}
1664
2d480e40
RD
1665#if wxUSE_NOTEBOOK
1666
1667wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
2d480e40 1668{
adbf2d73
VS
1669 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
1670 m_bookctrl = nb;
2d480e40
RD
1671}
1672
1673#endif // wxUSE_NOTEBOOOK
ade4eb65 1674#endif // wxUSE_BOOKCTRL
34c3ffca 1675
adbf2d73 1676#endif // WXWIN_COMPATIBILITY_2_4