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