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