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