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