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