]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
fixes for new lib dirs for wxMSW
[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{
9ef2e675
GT
566 wxSize size;
567 if (window->IsTopLevel())
568 size = FitSize( window );
569 else
570 size = GetMinWindowSize( window );
571
77424cfb 572 window->SetSize( size );
e5251d4f
VZ
573
574 return size;
5279a24d
RR
575}
576
566d84a7
RL
577void wxSizer::FitInside( wxWindow *window )
578{
579 wxSize size;
580 if (window->IsTopLevel())
581 size = VirtualFitSize( window );
582 else
583 size = GetMinClientSize( window );
584
585 window->SetVirtualSize( size );
586}
587
3417c2cd 588void wxSizer::Layout()
c62ac5b6 589{
42b4e99e 590 CalcMin();
c62ac5b6
RR
591 RecalcSizes();
592}
593
3417c2cd 594void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 595{
34c3ffca
RL
596 // Preserve the window's max size hints, but set the
597 // lower bound according to the sizer calculations.
598
e5251d4f
VZ
599 wxSize size = Fit( window );
600
34c3ffca
RL
601 window->SetSizeHints( size.x,
602 size.y,
603 window->GetMaxWidth(),
604 window->GetMaxHeight() );
5279a24d
RR
605}
606
566d84a7
RL
607void wxSizer::SetVirtualSizeHints( wxWindow *window )
608{
609 // Preserve the window's max size hints, but set the
610 // lower bound according to the sizer calculations.
611
612 FitInside( window );
613 wxSize size( window->GetVirtualSize() );
614 window->SetVirtualSizeHints( size.x,
615 size.y,
616 window->GetMaxWidth(),
617 window->GetMaxHeight() );
618}
619
9cbee2ce 620wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
65ba4113 621{
34c3ffca 622 return window->GetMaxSize();
65ba4113
GT
623}
624
3417c2cd 625wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 626{
12a3f227
RL
627 wxSize minSize( GetMinSize() );
628 wxSize size( window->GetSize() );
629 wxSize client_size( window->GetClientSize() );
630
77671fd2 631 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 632 minSize.y+size.y-client_size.y );
5279a24d
RR
633}
634
65ba4113
GT
635// Return a window size that will fit within the screens dimensions
636wxSize wxSizer::FitSize( wxWindow *window )
637{
638 wxSize size = GetMinWindowSize( window );
639 wxSize sizeMax = GetMaxWindowSize( window );
640
34c3ffca
RL
641 // Limit the size if sizeMax != wxDefaultSize
642
643 if ( size.x > sizeMax.x && sizeMax.x != -1 )
65ba4113 644 size.x = sizeMax.x;
34c3ffca 645 if ( size.y > sizeMax.y && sizeMax.y != -1 )
65ba4113
GT
646 size.y = sizeMax.y;
647
648 return size;
649}
650
9cbee2ce 651wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7
RL
652{
653 wxSize maxSize( window->GetMaxSize() );
654
655 if( maxSize != wxDefaultSize )
656 {
657 wxSize size( window->GetSize() );
658 wxSize client_size( window->GetClientSize() );
659
660 return wxSize( maxSize.x + client_size.x - size.x,
661 maxSize.y + client_size.y - size.y );
662 }
663 else
664 return wxDefaultSize;
665}
666
1b0674f7 667wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
668{
669 return GetMinSize(); // Already returns client size.
670}
671
672wxSize wxSizer::VirtualFitSize( wxWindow *window )
673{
674 wxSize size = GetMinClientSize( window );
675 wxSize sizeMax = GetMaxClientSize( window );
676
677 // Limit the size if sizeMax != wxDefaultSize
678
679 if ( size.x > sizeMax.x && sizeMax.x != -1 )
680 size.x = sizeMax.x;
681 if ( size.y > sizeMax.y && sizeMax.y != -1 )
682 size.y = sizeMax.y;
683
684 return size;
685}
686
3417c2cd 687void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
688{
689 m_position.x = x;
690 m_position.y = y;
691 m_size.x = width;
692 m_size.y = height;
2b5f62a0 693 Layout();
5279a24d
RR
694}
695
f6bcfd97 696wxSize wxSizer::GetMinSize()
3ca6a5f0 697{
f6bcfd97
BP
698 wxSize ret( CalcMin() );
699 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
700 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 701 return ret;
f6bcfd97
BP
702}
703
704void wxSizer::DoSetMinSize( int width, int height )
705{
706 m_minSize.x = width;
707 m_minSize.y = height;
708}
709
710bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
711{
12a3f227
RL
712 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
713
714 // Is it our immediate child?
f6bcfd97 715
222ed1d6 716 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
717 while (node)
718 {
12a3f227
RL
719 wxSizerItem *item = node->GetData();
720
3ca6a5f0
BP
721 if (item->GetWindow() == window)
722 {
f6bcfd97 723 item->SetInitSize( width, height );
e0d8fb45 724 return true;
3ca6a5f0 725 }
12a3f227 726 node = node->GetNext();
f6bcfd97
BP
727 }
728
12a3f227
RL
729 // No? Search any subsizers we own then
730
731 node = m_children.GetFirst();
f6bcfd97
BP
732 while (node)
733 {
12a3f227
RL
734 wxSizerItem *item = node->GetData();
735
736 if ( item->GetSizer() &&
737 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 738 {
12a3f227 739 // A child sizer found the requested windw, exit.
e0d8fb45 740 return true;
3ca6a5f0 741 }
12a3f227 742 node = node->GetNext();
f6bcfd97
BP
743 }
744
e0d8fb45 745 return false;
f6bcfd97
BP
746}
747
748bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
749{
12a3f227 750 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 751
12a3f227
RL
752 // Is it our immediate child?
753
222ed1d6 754 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
755 while (node)
756 {
12a3f227
RL
757 wxSizerItem *item = node->GetData();
758
3ca6a5f0
BP
759 if (item->GetSizer() == sizer)
760 {
f6bcfd97 761 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 762 return true;
3ca6a5f0 763 }
12a3f227 764 node = node->GetNext();
f6bcfd97
BP
765 }
766
12a3f227
RL
767 // No? Search any subsizers we own then
768
769 node = m_children.GetFirst();
f6bcfd97
BP
770 while (node)
771 {
12a3f227
RL
772 wxSizerItem *item = node->GetData();
773
774 if ( item->GetSizer() &&
775 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 776 {
12a3f227 777 // A child found the requested sizer, exit.
e0d8fb45 778 return true;
3ca6a5f0 779 }
12a3f227 780 node = node->GetNext();
f6bcfd97
BP
781 }
782
e0d8fb45 783 return false;
f6bcfd97
BP
784}
785
12a3f227 786bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 787{
222ed1d6 788 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
12a3f227 789
e0d8fb45 790 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
791
792 wxSizerItem *item = node->GetData();
f6bcfd97 793
f6bcfd97
BP
794 if (item->GetSizer())
795 {
0ca5105b 796 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
797 item->GetSizer()->DoSetMinSize( width, height );
798 }
799 else
800 {
0ca5105b 801 // ... but the minimal size of spacers and windows in stored in them
f6bcfd97
BP
802 item->SetInitSize( width, height );
803 }
804
e0d8fb45 805 return true;
f6bcfd97
BP
806}
807
12a3f227 808void wxSizer::Show( wxWindow *window, bool show )
2b5f62a0 809{
12a3f227
RL
810 wxASSERT_MSG( window, _T("Show for NULL window") );
811
222ed1d6 812 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
813 while (node)
814 {
12a3f227 815 wxSizerItem *item = node->GetData();
2b5f62a0 816
12a3f227 817 if (item->GetWindow() == window)
2b5f62a0 818 {
12a3f227
RL
819 item->Show( show );
820 break;
2b5f62a0 821 }
12a3f227 822 node = node->GetNext();
2b5f62a0
VZ
823 }
824}
825
12a3f227 826void wxSizer::Show( wxSizer *sizer, bool show )
2b5f62a0 827{
12a3f227
RL
828 wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
829
222ed1d6 830 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
831 while (node)
832 {
12a3f227 833 wxSizerItem *item = node->GetData();
2b5f62a0 834
12a3f227 835 if (item->GetSizer() == sizer)
2b5f62a0 836 {
12a3f227
RL
837 item->Show( show );
838 break;
2b5f62a0 839 }
12a3f227 840 node = node->GetNext();
2b5f62a0
VZ
841 }
842}
843
12a3f227 844void wxSizer::Show( size_t index, bool show )
2b5f62a0 845{
12a3f227
RL
846 wxCHECK_RET( index < m_children.GetCount(),
847 _T("Show index is out of range") );
2b5f62a0 848
12a3f227
RL
849 m_children.Item( index )->GetData()->Show( show );
850}
2b5f62a0 851
12a3f227
RL
852void wxSizer::ShowItems( bool show )
853{
222ed1d6 854 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
855 while (node)
856 {
857 node->GetData()->Show( show );
858 node = node->GetNext();
2b5f62a0
VZ
859 }
860}
861
9cbee2ce 862bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 863{
222ed1d6 864 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
865 while (node)
866 {
12a3f227 867 wxSizerItem *item = node->GetData();
dc259b79 868
12a3f227 869 if (item->GetWindow() == window)
2b5f62a0
VZ
870 {
871 return item->IsShown();
872 }
12a3f227 873 node = node->GetNext();
2b5f62a0
VZ
874 }
875
12a3f227
RL
876 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
877
e0d8fb45 878 return false;
2b5f62a0
VZ
879}
880
9cbee2ce 881bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 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
VZ
889 {
890 return item->IsShown();
891 }
12a3f227 892 node = node->GetNext();
2b5f62a0
VZ
893 }
894
12a3f227
RL
895 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
896
e0d8fb45 897 return false;
2b5f62a0
VZ
898}
899
9cbee2ce 900bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
901{
902 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 903 false,
12a3f227
RL
904 _T("IsShown index is out of range") );
905
906 return m_children.Item( index )->GetData()->IsShown();
907}
908
909
f6bcfd97
BP
910//---------------------------------------------------------------------------
911// wxGridSizer
912//---------------------------------------------------------------------------
913
914wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
12a3f227
RL
915 : m_rows( rows )
916 , m_cols( cols )
917 , m_vgap( vgap )
918 , m_hgap( hgap )
f6bcfd97 919{
f6bcfd97
BP
920}
921
922wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
12a3f227
RL
923 : m_rows( 0 )
924 , m_cols( cols )
925 , m_vgap( vgap )
926 , m_hgap( hgap )
f6bcfd97 927{
f6bcfd97
BP
928}
929
0ca5105b 930int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 931{
f6bcfd97 932 int nitems = m_children.GetCount();
2b5f62a0 933 if ( nitems)
0ca5105b
VZ
934 {
935 if ( m_cols )
936 {
937 ncols = m_cols;
938 nrows = (nitems + m_cols - 1) / m_cols;
939 }
940 else if ( m_rows )
941 {
942 ncols = (nitems + m_rows - 1) / m_rows;
943 nrows = m_rows;
944 }
945 else // 0 columns, 0 rows?
946 {
947 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 948
0ca5105b
VZ
949 nrows = ncols = 0;
950 }
951 }
952
953 return nitems;
954}
955
956void wxGridSizer::RecalcSizes()
957{
958 int nitems, nrows, ncols;
959 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
960 return;
f6bcfd97
BP
961
962 wxSize sz( GetSize() );
963 wxPoint pt( GetPosition() );
3ca6a5f0
BP
964
965 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
966 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
967
968 int x = pt.x;
969 for (int c = 0; c < ncols; c++)
970 {
971 int y = pt.y;
972 for (int r = 0; r < nrows; r++)
973 {
974 int i = r * ncols + c;
975 if (i < nitems)
976 {
222ed1d6 977 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
978
979 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 980
12a3f227 981 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
982 }
983 y = y + h + m_vgap;
984 }
985 x = x + w + m_hgap;
986 }
987}
988
989wxSize wxGridSizer::CalcMin()
990{
196be0f1
JS
991 int nrows, ncols;
992 if ( CalcRowsCols(nrows, ncols) == 0 )
0ca5105b 993 return wxSize(10, 10);
f6bcfd97 994
4f469fb5 995 // Find the max width and height for any component
f6bcfd97
BP
996 int w = 0;
997 int h = 0;
3ca6a5f0 998
222ed1d6 999 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1000 while (node)
1001 {
12a3f227
RL
1002 wxSizerItem *item = node->GetData();
1003 wxSize sz( item->CalcMin() );
1004
f6bcfd97
BP
1005 w = wxMax( w, sz.x );
1006 h = wxMax( h, sz.y );
3ca6a5f0 1007
12a3f227 1008 node = node->GetNext();
f6bcfd97 1009 }
3ca6a5f0 1010
12a3f227
RL
1011 return wxSize( ncols * w + (ncols-1) * m_hgap,
1012 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
1013}
1014
1015void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1016{
1017 wxPoint pt( x,y );
1018 wxSize sz( item->CalcMin() );
1019 int flag = item->GetFlag();
1020
1021 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1022 {
1023 sz = wxSize(w, h);
1024 }
1025 else
1026 {
1027 if (flag & wxALIGN_CENTER_HORIZONTAL)
1028 {
1029 pt.x = x + (w - sz.x) / 2;
1030 }
1031 else if (flag & wxALIGN_RIGHT)
1032 {
1033 pt.x = x + (w - sz.x);
1034 }
3ca6a5f0 1035
f6bcfd97
BP
1036 if (flag & wxALIGN_CENTER_VERTICAL)
1037 {
1038 pt.y = y + (h - sz.y) / 2;
1039 }
1040 else if (flag & wxALIGN_BOTTOM)
1041 {
1042 pt.y = y + (h - sz.y);
1043 }
1044 }
3ca6a5f0 1045
f6bcfd97
BP
1046 item->SetDimension(pt, sz);
1047}
1048
1049//---------------------------------------------------------------------------
1050// wxFlexGridSizer
1051//---------------------------------------------------------------------------
1052
1053wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1054 : wxGridSizer( rows, cols, vgap, hgap ),
1055 m_flexDirection(wxBOTH),
1056 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1057{
f6bcfd97
BP
1058}
1059
1060wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1061 : wxGridSizer( cols, vgap, hgap ),
1062 m_flexDirection(wxBOTH),
1063 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1064{
f6bcfd97 1065}
3ca6a5f0 1066
f6bcfd97
BP
1067wxFlexGridSizer::~wxFlexGridSizer()
1068{
f6bcfd97
BP
1069}
1070
1071void wxFlexGridSizer::RecalcSizes()
1072{
0ca5105b
VZ
1073 int nitems, nrows, ncols;
1074 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
f6bcfd97
BP
1075 return;
1076
f6bcfd97
BP
1077 wxSize sz( GetSize() );
1078 wxSize minsz( CalcMin() );
1079 wxPoint pt( GetPosition() );
0ca5105b 1080
5d76f462 1081 // what to do with the rows? by default, resize them proportionally
55f9f0cb 1082 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
5d76f462 1083 {
55f9f0cb
VZ
1084 int sum_proportions = 0;
1085 int growable_space = 0;
1086 int num = 0;
1087 size_t idx;
5d76f462
VZ
1088 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1089 {
2d480e40 1090 // Since the number of rows/columns can change as items are inserted/deleted, we need
55f9f0cb 1091 // to verify at runtime that the requested growable rows/columns are still valid.
2d480e40 1092 if (m_growableRows[idx] >= nrows)
55f9f0cb
VZ
1093 continue;
1094 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1095 // This causes the row/column to be hidden completely.
2d480e40 1096 if (m_rowHeights[ m_growableRows[idx] ] == -1)
55f9f0cb
VZ
1097 continue;
1098 sum_proportions += m_growableRowsProportions[idx];
1099 growable_space += m_rowHeights[ m_growableRows[idx] ];
1100 num++;
5d76f462
VZ
1101 }
1102
55f9f0cb 1103 if (num > 0)
5d76f462 1104 {
55f9f0cb 1105 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
e8800dcf 1106 {
2d480e40 1107 if (m_growableRows[idx] >= nrows )
55f9f0cb 1108 continue;
2d480e40 1109 if (m_rowHeights[ m_growableRows[idx] ] == -1)
55f9f0cb 1110 m_rowHeights[ m_growableRows[idx] ] = 0;
e8800dcf 1111 else
55f9f0cb
VZ
1112 {
1113 int delta = (sz.y - minsz.y);
1114 if (sum_proportions == 0)
1115 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1116 else
1117 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1118 m_rowHeights[ m_growableRows[idx] ] = delta;
1119 }
e8800dcf 1120 }
5d76f462 1121 }
5d76f462
VZ
1122 }
1123 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
f6bcfd97 1124 {
5d76f462
VZ
1125 // rounding problem?
1126 for ( int row = 0; row < nrows; ++row )
1127 m_rowHeights[ row ] = sz.y / nrows;
f6bcfd97 1128 }
3ca6a5f0 1129
5d76f462 1130 // the same logic as above but for the columns
55f9f0cb 1131 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
5d76f462 1132 {
55f9f0cb
VZ
1133 int sum_proportions = 0;
1134 int growable_space = 0;
1135 int num = 0;
1136 size_t idx;
5d76f462
VZ
1137 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1138 {
2d480e40 1139 // Since the number of rows/columns can change as items are inserted/deleted, we need
55f9f0cb 1140 // to verify at runtime that the requested growable rows/columns are still valid.
2d480e40 1141 if (m_growableCols[idx] >= ncols)
55f9f0cb
VZ
1142 continue;
1143 // If all items in a row/column are hidden, that row/column will have a dimension of -1.
1144 // This causes the column to be hidden completely.
2d480e40 1145 if (m_colWidths[ m_growableCols[idx] ] == -1)
55f9f0cb
VZ
1146 continue;
1147 sum_proportions += m_growableColsProportions[idx];
1148 // wtb 5/12/02 bugfix - was m_ColWidths[idx]!!
1149 growable_space += m_colWidths[ m_growableCols[idx] ];
1150 num++;
5d76f462
VZ
1151 }
1152
55f9f0cb 1153 if (num > 0)
5d76f462 1154 {
55f9f0cb 1155 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
e8800dcf 1156 {
2d480e40 1157 if (m_growableCols[idx] >= ncols )
55f9f0cb 1158 continue;
2d480e40 1159 if (m_colWidths[ m_growableCols[idx] ] == -1)
55f9f0cb
VZ
1160 m_colWidths[ m_growableCols[idx] ] = 0;
1161 else
1162 {
1163 int delta = (sz.x - minsz.x);
1164 if (sum_proportions == 0)
1165 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1166 else
1167 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1168 m_colWidths[ m_growableCols[idx] ] = delta;
1169 }
e8800dcf 1170 }
5d76f462
VZ
1171 }
1172 }
1173 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
f6bcfd97 1174 {
5d76f462
VZ
1175 for ( int col=0; col < ncols; ++col )
1176 m_colWidths[ col ] = sz.x / ncols;
f6bcfd97 1177 }
3ca6a5f0 1178
f6bcfd97
BP
1179 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1180
1181 int x = pt.x;
1182 for (int c = 0; c < ncols; c++)
1183 {
1184 int y = pt.y;
1185 for (int r = 0; r < nrows; r++)
1186 {
1187 int i = r * ncols + c;
1188 if (i < nitems)
1189 {
222ed1d6 1190 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1191
1192 wxASSERT_MSG( node, _T("Failed to find node") );
3ca6a5f0 1193
f6bcfd97
BP
1194 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1195 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
3ca6a5f0 1196
12a3f227 1197 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1198 }
1199 y = y + m_rowHeights[r] + m_vgap;
1200 }
1201 x = x + m_colWidths[c] + m_hgap;
1202 }
1203}
1204
1205wxSize wxFlexGridSizer::CalcMin()
1206{
150c8d89
RL
1207 int nrows,
1208 ncols;
1209 size_t i, s;
1210
55f9f0cb 1211 // Number of rows/columns can change as items are added or removed.
5d76f462
VZ
1212 if ( !CalcRowsCols(nrows, ncols) )
1213 return wxSize(10, 10);
f6bcfd97 1214
5d76f462
VZ
1215 m_rowHeights.SetCount(nrows);
1216 m_colWidths.SetCount(ncols);
3ca6a5f0 1217
2d480e40 1218 // We have to recalcuate the sizes in case an item has wxADJUST_MINSIZE, has changed
55f9f0cb 1219 // minimum size since the previous layout, or has been hidden using wxSizer::Show().
2d480e40 1220 // If all the items in a row/column are hidden, the final dimension of the row/column
55f9f0cb
VZ
1221 // will be -1, indicating that the column itself is hidden.
1222 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1223 m_rowHeights[ i ] = -1;
1224 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1225 m_colWidths[ i ] = -1;
1226
222ed1d6 1227 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227 1228
150c8d89 1229 i = 0;
f6bcfd97
BP
1230 while (node)
1231 {
12a3f227 1232 wxSizerItem *item = node->GetData();
55f9f0cb
VZ
1233 if ( item->IsShown() )
1234 {
1235 wxSize sz( item->CalcMin() );
1236 int row = i / ncols;
1237 int col = i % ncols;
12a3f227 1238
55f9f0cb
VZ
1239 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1240 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1241 }
3ca6a5f0 1242
12a3f227 1243 node = node->GetNext();
f6bcfd97
BP
1244 i++;
1245 }
3ca6a5f0 1246
5d76f462
VZ
1247 // the logic above works when we resize flexibly in both directions but
1248 // maybe this is not the case
1249 if ( m_flexDirection != wxBOTH )
1250 {
1251 // select the array corresponding to the direction in which we do *not*
1252 // resize flexibly
1253 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1254 : m_rowHeights;
1255
1256 const int count = array.GetCount();
1257
1258 // find the largest value in this array
55f9f0cb 1259 int n, largest = 0;
5d76f462
VZ
1260 for ( n = 0; n < count; ++n )
1261 {
1262 if ( array[n] > largest )
1263 largest = array[n];
1264 }
1265
1266 // and now fill it with the largest value
1267 for ( n = 0; n < count; ++n )
1268 {
1269 array[n] = largest;
1270 }
1271 }
1272
55f9f0cb
VZ
1273 // Sum total minimum size, including gaps between rows/columns.
1274 // -1 is used as a magic number meaning empty column.
f6bcfd97 1275 int width = 0;
0ca5105b 1276 for (int col = 0; col < ncols; col++)
2d480e40 1277 if ( m_colWidths[ col ] != -1 )
55f9f0cb 1278 width += m_colWidths[ col ] + ( col == ncols-1 ? 0 : m_hgap );
3ca6a5f0 1279
f6bcfd97 1280 int height = 0;
0ca5105b 1281 for (int row = 0; row < nrows; row++)
55f9f0cb
VZ
1282 if ( m_rowHeights[ row ] != -1 )
1283 height += m_rowHeights[ row ] + ( row == nrows-1 ? 0 : m_vgap );
3ca6a5f0 1284
55f9f0cb 1285 return wxSize( width, height );
f6bcfd97
BP
1286}
1287
e8800dcf 1288void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1289{
1290 m_growableRows.Add( idx );
e8800dcf 1291 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1292}
1293
3ca6a5f0 1294void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
f6bcfd97
BP
1295{
1296}
1297
e8800dcf 1298void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1299{
1300 m_growableCols.Add( idx );
e8800dcf 1301 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1302}
1303
3ca6a5f0 1304void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
f6bcfd97
BP
1305{
1306}
1307
c62ac5b6 1308//---------------------------------------------------------------------------
92afa2b1 1309// wxBoxSizer
61d514bb
RR
1310//---------------------------------------------------------------------------
1311
92afa2b1 1312wxBoxSizer::wxBoxSizer( int orient )
12a3f227 1313 : m_orient( orient )
61d514bb 1314{
61d514bb
RR
1315}
1316
92afa2b1 1317void wxBoxSizer::RecalcSizes()
61d514bb
RR
1318{
1319 if (m_children.GetCount() == 0)
61d514bb 1320 return;
0c0d686f 1321
61d514bb
RR
1322 int delta = 0;
1323 int extra = 0;
1324 if (m_stretchable)
1325 {
1326 if (m_orient == wxHORIZONTAL)
1327 {
1328 delta = (m_size.x - m_fixedWidth) / m_stretchable;
1329 extra = (m_size.x - m_fixedWidth) % m_stretchable;
3ca6a5f0
BP
1330 }
1331 else
1332 {
61d514bb
RR
1333 delta = (m_size.y - m_fixedHeight) / m_stretchable;
1334 extra = (m_size.y - m_fixedHeight) % m_stretchable;
3ca6a5f0 1335 }
61d514bb 1336 }
0c0d686f 1337
61d514bb 1338 wxPoint pt( m_position );
0c0d686f 1339
222ed1d6 1340 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
61d514bb
RR
1341 while (node)
1342 {
12a3f227
RL
1343 wxSizerItem *item = node->GetData();
1344
2b5f62a0 1345 if (item->IsShown())
3ca6a5f0 1346 {
2b5f62a0 1347 int weight = 1;
12a3f227
RL
1348 if (item->GetProportion())
1349 weight = item->GetProportion();
3ca6a5f0 1350
2b5f62a0 1351 wxSize size( item->CalcMin() );
3ca6a5f0 1352
2b5f62a0 1353 if (m_orient == wxVERTICAL)
3ca6a5f0 1354 {
2b5f62a0 1355 wxCoord height = size.y;
12a3f227 1356 if (item->GetProportion())
2b5f62a0
VZ
1357 {
1358 height = (delta * weight) + extra;
1359 extra = 0; // only the first item will get the remainder as extra size
1360 }
1361
1362 wxPoint child_pos( pt );
1363 wxSize child_size( wxSize( size.x, height) );
1364
1365 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1366 child_size.x = m_size.x;
1367 else if (item->GetFlag() & wxALIGN_RIGHT)
1368 child_pos.x += m_size.x - size.x;
1369 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1370 // XXX wxCENTER is added for backward compatibility;
1371 // wxALIGN_CENTER should be used in new code
1372 child_pos.x += (m_size.x - size.x) / 2;
1373
1374 item->SetDimension( child_pos, child_size );
1375
1376 pt.y += height;
1377 }
1378 else
1379 {
1380 wxCoord width = size.x;
12a3f227 1381 if (item->GetProportion())
2b5f62a0
VZ
1382 {
1383 width = (delta * weight) + extra;
1384 extra = 0; // only the first item will get the remainder as extra size
1385 }
1386
1387 wxPoint child_pos( pt );
1388 wxSize child_size( wxSize(width, size.y) );
1389
1390 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1391 child_size.y = m_size.y;
1392 else if (item->GetFlag() & wxALIGN_BOTTOM)
1393 child_pos.y += m_size.y - size.y;
1394 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1395 // XXX wxCENTER is added for backward compatibility;
1396 // wxALIGN_CENTER should be used in new code
1397 child_pos.y += (m_size.y - size.y) / 2;
1398
1399 item->SetDimension( child_pos, child_size );
1400
1401 pt.x += width;
3ca6a5f0 1402 }
3ca6a5f0
BP
1403 }
1404
12a3f227 1405 node = node->GetNext();
61d514bb
RR
1406 }
1407}
1408
92afa2b1 1409wxSize wxBoxSizer::CalcMin()
61d514bb
RR
1410{
1411 if (m_children.GetCount() == 0)
c7a9fa36 1412 return wxSize(10,10);
0c0d686f 1413
61d514bb
RR
1414 m_stretchable = 0;
1415 m_minWidth = 0;
1416 m_minHeight = 0;
1417 m_fixedWidth = 0;
1418 m_fixedHeight = 0;
0c0d686f 1419
f98de448 1420 // Find how long each stretch unit needs to be
12a3f227 1421 int stretchSize = 1;
222ed1d6 1422 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227 1423
61d514bb 1424 while (node)
f98de448 1425 {
12a3f227
RL
1426 wxSizerItem *item = node->GetData();
1427
1428 if (item->IsShown() && item->GetProportion() != 0)
f98de448 1429 {
12a3f227 1430 int stretch = item->GetProportion();
f98de448
RD
1431 wxSize size( item->CalcMin() );
1432 int sizePerStretch;
1433 // Integer division rounded up is (a + b - 1) / b
1434 if (m_orient == wxHORIZONTAL)
1435 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1436 else
1437 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1438 if (sizePerStretch > stretchSize)
1439 stretchSize = sizePerStretch;
1440 }
12a3f227 1441 node = node->GetNext();
f98de448 1442 }
12a3f227 1443
4f469fb5
RR
1444 // Calculate overall minimum size
1445 node = m_children.GetFirst();
f98de448 1446 while (node)
61d514bb 1447 {
12a3f227
RL
1448 wxSizerItem *item = node->GetData();
1449
2b5f62a0 1450 if (item->IsShown())
f98de448 1451 {
12a3f227 1452 m_stretchable += item->GetProportion();
3ca6a5f0 1453
2b5f62a0 1454 wxSize size( item->CalcMin() );
12a3f227 1455 if (item->GetProportion() != 0)
2b5f62a0
VZ
1456 {
1457 if (m_orient == wxHORIZONTAL)
12a3f227 1458 size.x = stretchSize * item->GetProportion();
2b5f62a0 1459 else
12a3f227 1460 size.y = stretchSize * item->GetProportion();
2b5f62a0 1461 }
3ca6a5f0 1462
2b5f62a0 1463 if (m_orient == wxHORIZONTAL)
3ca6a5f0 1464 {
2b5f62a0
VZ
1465 m_minWidth += size.x;
1466 m_minHeight = wxMax( m_minHeight, size.y );
3ca6a5f0
BP
1467 }
1468 else
33ac7e6f 1469 {
2b5f62a0
VZ
1470 m_minHeight += size.y;
1471 m_minWidth = wxMax( m_minWidth, size.x );
3ca6a5f0 1472 }
3ca6a5f0 1473
12a3f227 1474 if (item->GetProportion() == 0)
2b5f62a0
VZ
1475 {
1476 if (m_orient == wxVERTICAL)
1477 {
1478 m_fixedHeight += size.y;
1479 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1480 }
1481 else
1482 {
1483 m_fixedWidth += size.x;
1484 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1485 }
1486 }
1487 }
12a3f227 1488 node = node->GetNext();
61d514bb 1489 }
0c0d686f 1490
61d514bb
RR
1491 return wxSize( m_minWidth, m_minHeight );
1492}
27ea1d8a
RR
1493
1494//---------------------------------------------------------------------------
1495// wxStaticBoxSizer
1496//---------------------------------------------------------------------------
1497
1e6feb95
VZ
1498#if wxUSE_STATBOX
1499
27ea1d8a 1500wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
12a3f227
RL
1501 : wxBoxSizer( orient )
1502 , m_staticBox( box )
27ea1d8a 1503{
223d09f6 1504 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
27ea1d8a 1505}
0c0d686f 1506
12a3f227
RL
1507static void GetStaticBoxBorders( wxStaticBox *box,
1508 int *borderTop,
1509 int *borderOther)
84028727
VZ
1510{
1511 // this has to be done platform by platform as there is no way to
1512 // guess the thickness of a wxStaticBox border
ec4e4a14
DE
1513#ifdef __WXCOCOA__
1514 box->GetBordersForSizer(borderTop,borderOther);
1515#else // __WXCOCOA__
84028727
VZ
1516#ifdef __WXGTK__
1517 if ( box->GetLabel().IsEmpty() )
1518 *borderTop = 5;
1519 else
1520#endif // __WXGTK__
f2b99f63
JS
1521 *borderTop = box->GetCharHeight();
1522
84028727 1523 *borderOther = 5;
ec4e4a14 1524#endif // __WXCOCOA__
84028727
VZ
1525}
1526
27ea1d8a
RR
1527void wxStaticBoxSizer::RecalcSizes()
1528{
84028727
VZ
1529 int top_border, other_border;
1530 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
1531
1532 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 1533
27ea1d8a
RR
1534 wxPoint old_pos( m_position );
1535 m_position.x += other_border;
1536 m_position.y += top_border;
1537 wxSize old_size( m_size );
1538 m_size.x -= 2*other_border;
1539 m_size.y -= top_border + other_border;
0c0d686f 1540
27ea1d8a 1541 wxBoxSizer::RecalcSizes();
0c0d686f 1542
27ea1d8a
RR
1543 m_position = old_pos;
1544 m_size = old_size;
1545}
1546
1547wxSize wxStaticBoxSizer::CalcMin()
1548{
84028727
VZ
1549 int top_border, other_border;
1550 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 1551
27ea1d8a 1552 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 1553 ret.x += 2*other_border;
27ea1d8a 1554 ret.y += other_border + top_border;
0c0d686f 1555
27ea1d8a
RR
1556 return ret;
1557}
83edc0a5 1558
1e6feb95
VZ
1559#endif // wxUSE_STATBOX
1560
ade4eb65 1561// ----------------------------------------------------------------------------
83edc0a5 1562// wxNotebookSizer
ade4eb65 1563// ----------------------------------------------------------------------------
83edc0a5 1564
ade4eb65 1565#if wxUSE_BOOKCTRL
60be2f47 1566
ade4eb65
VZ
1567wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrl *bookctrl)
1568 : m_bookctrl(bookctrl)
83edc0a5 1569{
ade4eb65 1570 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
83edc0a5
RR
1571}
1572
ade4eb65 1573void wxBookCtrlSizer::RecalcSizes()
83edc0a5 1574{
ade4eb65 1575 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
83edc0a5
RR
1576}
1577
ade4eb65 1578wxSize wxBookCtrlSizer::CalcMin()
83edc0a5 1579{
ade4eb65 1580 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
1e6feb95
VZ
1581
1582 sizeBorder.x += 5;
1583 sizeBorder.y += 5;
3ca6a5f0 1584
ade4eb65 1585 if ( m_bookctrl->GetPageCount() == 0 )
1e6feb95
VZ
1586 {
1587 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1588 }
83edc0a5
RR
1589
1590 int maxX = 0;
1591 int maxY = 0;
1592
ade4eb65
VZ
1593 wxWindowList::compatibility_iterator
1594 node = m_bookctrl->GetChildren().GetFirst();
83edc0a5
RR
1595 while (node)
1596 {
1597 wxWindow *item = node->GetData();
3ca6a5f0
BP
1598 wxSizer *itemsizer = item->GetSizer();
1599
1600 if (itemsizer)
1601 {
83edc0a5 1602 wxSize subsize( itemsizer->CalcMin() );
83edc0a5 1603
1e6feb95
VZ
1604 if (subsize.x > maxX)
1605 maxX = subsize.x;
1606 if (subsize.y > maxY)
1607 maxY = subsize.y;
3ca6a5f0
BP
1608 }
1609
1610 node = node->GetNext();
83edc0a5
RR
1611 }
1612
1e6feb95 1613 return wxSize( maxX, maxY ) + sizeBorder;
83edc0a5
RR
1614}
1615
2d480e40
RD
1616
1617#if wxUSE_NOTEBOOK
1618
1619wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
1620 : wxBookCtrlSizer(nb)
1621{
1622}
1623
1624#endif // wxUSE_NOTEBOOOK
ade4eb65 1625#endif // wxUSE_BOOKCTRL
34c3ffca 1626