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