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