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