]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
Fixed several style, paste and undo bugs
[wxWidgets.git] / src / common / sizer.cpp
CommitLineData
5279a24d 1/////////////////////////////////////////////////////////////////////////////
ca3e85cf 2// Name: src/common/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
77671fd2
VZ
13// For compilers that support precompilation, includes "wx.h".
14#include "wx/wxprec.h"
15
16#ifdef __BORLANDC__
17 #pragma hdrstop
18#endif
19
98018a4b 20#include "wx/display.h"
ed2fbeb8
WS
21#include "wx/sizer.h"
22
0f769aab
WS
23#ifndef WX_PRECOMP
24 #include "wx/string.h"
25 #include "wx/intl.h"
2fb18bf4 26 #include "wx/math.h"
de6185e2 27 #include "wx/utils.h"
9eddec69 28 #include "wx/settings.h"
ca8d899f 29 #include "wx/button.h"
876cd6f7 30 #include "wx/statbox.h"
4107600f 31 #include "wx/toplevel.h"
0f769aab
WS
32#endif // WX_PRECOMP
33
c54b92d3 34#include "wx/listimpl.cpp"
88a7a4e1 35
5279a24d 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
974c2a59 47#if wxUSE_BUTTON
acf2ac37 48IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
974c2a59 49#endif
0c0d686f 50
259c43f6 51WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
12a3f227 52
066f1b7a 53/*
8b2bac62
WS
54 TODO PROPERTIES
55 sizeritem
56 object
57 object_ref
58 minsize
59 option
60 flag
61 border
066f1b7a 62 spacer
8b2bac62
WS
63 option
64 flag
65 borfder
66 boxsizer
67 orient
066f1b7a 68 staticboxsizer
8b2bac62
WS
69 orient
70 label
71 gridsizer
72 rows
73 cols
74 vgap
75 hgap
76 flexgridsizer
77 rows
78 cols
79 vgap
80 hgap
81 growablerows
82 growablecols
066f1b7a
SC
83 minsize
84*/
ccbc8038 85
50c06297 86// ----------------------------------------------------------------------------
3417c2cd 87// wxSizerItem
50c06297 88// ----------------------------------------------------------------------------
ccbc8038
VZ
89
90void wxSizerItem::Init(const wxSizerFlags& flags)
91{
92 Init();
93
94 m_proportion = flags.GetProportion();
95 m_flag = flags.GetFlags();
96 m_border = flags.GetBorderInPixels();
97}
98
50c06297
VZ
99wxSizerItem::wxSizerItem()
100{
101 Init();
102
103 m_proportion = 0;
104 m_border = 0;
105 m_flag = 0;
86909f4c 106 m_id = wxID_NONE;
50c06297
VZ
107}
108
109// window item
4dd10327 110void wxSizerItem::DoSetWindow(wxWindow *window)
50c06297
VZ
111{
112 wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") );
113
114 m_kind = Item_Window;
115 m_window = window;
116
117 // window doesn't become smaller than its initial size, whatever happens
ba763a45 118 m_minSize = window->GetSize();
8b2bac62 119
50c06297
VZ
120 if ( m_flag & wxFIXED_MINSIZE )
121 window->SetMinSize(m_minSize);
122
36461f58 123 // aspect ratio calculated from initial size
50c06297
VZ
124 SetRatio(m_minSize);
125}
36461f58 126
50c06297
VZ
127wxSizerItem::wxSizerItem(wxWindow *window,
128 int proportion,
129 int flag,
130 int border,
131 wxObject* userData)
4dd10327
VZ
132 : m_kind(Item_None),
133 m_proportion(proportion),
50c06297
VZ
134 m_border(border),
135 m_flag(flag),
86909f4c 136 m_id(wxID_NONE),
50c06297
VZ
137 m_userData(userData)
138{
4dd10327 139 DoSetWindow(window);
5279a24d
RR
140}
141
50c06297 142// sizer item
4dd10327 143void wxSizerItem::DoSetSizer(wxSizer *sizer)
5279a24d 144{
50c06297
VZ
145 m_kind = Item_Sizer;
146 m_sizer = sizer;
5279a24d
RR
147}
148
50c06297
VZ
149wxSizerItem::wxSizerItem(wxSizer *sizer,
150 int proportion,
151 int flag,
152 int border,
153 wxObject* userData)
4dd10327
VZ
154 : m_kind(Item_None),
155 m_sizer(NULL),
156 m_proportion(proportion),
50c06297
VZ
157 m_border(border),
158 m_flag(flag),
86909f4c 159 m_id(wxID_NONE),
50c06297
VZ
160 m_ratio(0.0),
161 m_userData(userData)
20b35a69 162{
4dd10327 163 DoSetSizer(sizer);
ccbc8038 164
50c06297
VZ
165 // m_minSize is set later
166}
167
168// spacer item
4dd10327 169void wxSizerItem::DoSetSpacer(const wxSize& size)
50c06297
VZ
170{
171 m_kind = Item_Spacer;
172 m_spacer = new wxSizerSpacer(size);
173 m_minSize = size;
174 SetRatio(size);
175}
176
177wxSizerItem::wxSizerItem(int width,
178 int height,
179 int proportion,
180 int flag,
181 int border,
182 wxObject* userData)
4dd10327
VZ
183 : m_kind(Item_None),
184 m_sizer(NULL),
185 m_minSize(width, height), // minimal size is the initial size
50c06297
VZ
186 m_proportion(proportion),
187 m_border(border),
188 m_flag(flag),
86909f4c 189 m_id(wxID_NONE),
50c06297
VZ
190 m_userData(userData)
191{
4dd10327 192 DoSetSpacer(wxSize(width, height));
20b35a69
RD
193}
194
0c0d686f
RD
195wxSizerItem::~wxSizerItem()
196{
f91e8382 197 delete m_userData;
4dd10327
VZ
198 Free();
199}
f91e8382 200
4dd10327
VZ
201void wxSizerItem::Free()
202{
50c06297 203 switch ( m_kind )
f91e8382 204 {
50c06297
VZ
205 case Item_None:
206 break;
207
208 case Item_Window:
209 m_window->SetContainingSizer(NULL);
210 break;
211
212 case Item_Sizer:
213 delete m_sizer;
214 break;
215
216 case Item_Spacer:
217 delete m_spacer;
218 break;
219
220 case Item_Max:
221 default:
222 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
f91e8382 223 }
4dd10327
VZ
224
225 m_kind = Item_None;
0c0d686f
RD
226}
227
50c06297
VZ
228wxSize wxSizerItem::GetSpacer() const
229{
230 wxSize size;
231 if ( m_kind == Item_Spacer )
232 size = m_spacer->GetSize();
233
234 return size;
235}
236
0c0d686f 237
9cbee2ce 238wxSize wxSizerItem::GetSize() const
5279a24d 239{
d597fcb7 240 wxSize ret;
50c06297
VZ
241 switch ( m_kind )
242 {
243 case Item_None:
244 break;
245
246 case Item_Window:
247 ret = m_window->GetSize();
248 break;
249
250 case Item_Sizer:
251 ret = m_sizer->GetSize();
252 break;
253
254 case Item_Spacer:
255 ret = m_spacer->GetSize();
256 break;
257
258 case Item_Max:
259 default:
260 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
261 }
0c0d686f 262
d597fcb7
RR
263 if (m_flag & wxWEST)
264 ret.x += m_border;
265 if (m_flag & wxEAST)
266 ret.x += m_border;
267 if (m_flag & wxNORTH)
268 ret.y += m_border;
269 if (m_flag & wxSOUTH)
270 ret.y += m_border;
0c0d686f 271
d597fcb7 272 return ret;
5279a24d
RR
273}
274
15f7c305
RR
275bool wxSizerItem::InformFirstDirection(int direction, int size, int availableOtherDir)
276{
3d2085a4
VZ
277 // The size that come here will be including borders. Child items should get it
278 // without borders.
279 if( size>0 )
280 {
281 if( direction==wxHORIZONTAL )
282 {
283 if (m_flag & wxWEST)
284 size -= m_border;
285 if (m_flag & wxEAST)
286 size -= m_border;
287 }
288 else if( direction==wxVERTICAL )
289 {
290 if (m_flag & wxNORTH)
291 size -= m_border;
292 if (m_flag & wxSOUTH)
293 size -= m_border;
294 }
295 }
296
15f7c305
RR
297 bool didUse = false;
298 // Pass the information along to the held object
299 if (IsSizer())
300 {
301 didUse = GetSizer()->InformFirstDirection(direction,size,availableOtherDir);
302 if (didUse)
3d2085a4 303 m_minSize = GetSizer()->CalcMin();
15f7c305
RR
304 }
305 else if (IsWindow())
306 {
307 didUse = GetWindow()->InformFirstDirection(direction,size,availableOtherDir);
308 if (didUse)
309 m_minSize = m_window->GetEffectiveMinSize();
3d2085a4
VZ
310
311 // This information is useful for items with wxSHAPED flag, since
312 // we can request an optimal min size for such an item. Even if
313 // we overwrite the m_minSize member here, we can read it back from
314 // the owned window (happens automatically).
315 if( (m_flag & wxSHAPED) && (m_flag & wxEXPAND) && direction )
316 {
317 if( !wxIsNullDouble(m_ratio) )
318 {
319 wxCHECK_MSG( (m_proportion==0), false, _T("Shaped item, non-zero proportion in wxSizerItem::InformFirstDirection()") );
320 if( direction==wxHORIZONTAL && !wxIsNullDouble(m_ratio) )
321 {
322 // Clip size so that we don't take too much
323 if( availableOtherDir>=0 && int(size/m_ratio)-m_minSize.y>availableOtherDir )
324 size = int((availableOtherDir+m_minSize.y)*m_ratio);
325 m_minSize = wxSize(size,int(size/m_ratio));
326 }
327 else if( direction==wxVERTICAL )
328 {
329 // Clip size so that we don't take too much
330 if( availableOtherDir>=0 && int(size*m_ratio)-m_minSize.x>availableOtherDir )
331 size = int((availableOtherDir+m_minSize.x)/m_ratio);
332 m_minSize = wxSize(int(size*m_ratio),size);
333 }
334 didUse = true;
335 }
336 }
337 }
338
15f7c305
RR
339 return didUse;
340}
341
3417c2cd 342wxSize wxSizerItem::CalcMin()
c62ac5b6 343{
3417c2cd 344 if (IsSizer())
be2577e4 345 {
ba763a45 346 m_minSize = m_sizer->GetMinSize();
d13d8d4e 347
be2577e4
RD
348 // if we have to preserve aspect ratio _AND_ this is
349 // the first-time calculation, consider ret to be initial size
2fb18bf4 350 if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
36461f58 351 SetRatio(m_minSize);
be2577e4 352 }
ba763a45 353 else if ( IsWindow() )
d13d8d4e 354 {
ba763a45
RD
355 // Since the size of the window may change during runtime, we
356 // should use the current minimal/best size.
170acdc9 357 m_minSize = m_window->GetEffectiveMinSize();
d13d8d4e 358 }
0c0d686f 359
ba763a45
RD
360 return GetMinSizeWithBorder();
361}
362
363wxSize wxSizerItem::GetMinSizeWithBorder() const
364{
365 wxSize ret = m_minSize;
366
d597fcb7
RR
367 if (m_flag & wxWEST)
368 ret.x += m_border;
369 if (m_flag & wxEAST)
370 ret.x += m_border;
371 if (m_flag & wxNORTH)
372 ret.y += m_border;
373 if (m_flag & wxSOUTH)
374 ret.y += m_border;
8b2bac62 375
d597fcb7 376 return ret;
c62ac5b6
RR
377}
378
ba763a45 379
fbfb8bcc 380void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
c62ac5b6 381{
fbfb8bcc
VZ
382 wxPoint pos = pos_;
383 wxSize size = size_;
cdddaeea 384 if (m_flag & wxSHAPED)
d597fcb7 385 {
be2577e4
RD
386 // adjust aspect ratio
387 int rwidth = (int) (size.y * m_ratio);
cdddaeea
VZ
388 if (rwidth > size.x)
389 {
be2577e4
RD
390 // fit horizontally
391 int rheight = (int) (size.x / m_ratio);
392 // add vertical space
393 if (m_flag & wxALIGN_CENTER_VERTICAL)
394 pos.y += (size.y - rheight) / 2;
395 else if (m_flag & wxALIGN_BOTTOM)
396 pos.y += (size.y - rheight);
397 // use reduced dimensions
398 size.y =rheight;
cdddaeea
VZ
399 }
400 else if (rwidth < size.x)
401 {
be2577e4
RD
402 // add horizontal space
403 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
404 pos.x += (size.x - rwidth) / 2;
405 else if (m_flag & wxALIGN_RIGHT)
406 pos.x += (size.x - rwidth);
407 size.x = rwidth;
408 }
409 }
33ac7e6f 410
cdddaeea
VZ
411 // This is what GetPosition() returns. Since we calculate
412 // borders afterwards, GetPosition() will be the left/top
413 // corner of the surrounding border.
414 m_pos = pos;
415
416 if (m_flag & wxWEST)
417 {
418 pos.x += m_border;
419 size.x -= m_border;
420 }
421 if (m_flag & wxEAST)
422 {
423 size.x -= m_border;
424 }
425 if (m_flag & wxNORTH)
426 {
427 pos.y += m_border;
428 size.y -= m_border;
429 }
430 if (m_flag & wxSOUTH)
431 {
432 size.y -= m_border;
433 }
0c0d686f 434
003b64a7
PC
435 if (size.x < 0)
436 size.x = 0;
437 if (size.y < 0)
438 size.y = 0;
439
50c06297 440 m_rect = wxRect(pos, size);
0c0d686f 441
50c06297
VZ
442 switch ( m_kind )
443 {
444 case Item_None:
445 wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
446 break;
447
448 case Item_Window:
449 m_window->SetSize(pos.x, pos.y, size.x, size.y,
450 wxSIZE_ALLOW_MINUS_ONE);
451 break;
452
453 case Item_Sizer:
454 m_sizer->SetDimension(pos.x, pos.y, size.x, size.y);
455 break;
456
457 case Item_Spacer:
458 m_spacer->SetSize(size);
459 break;
460
461 case Item_Max:
462 default:
463 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
464 }
c62ac5b6
RR
465}
466
84f7908b
RR
467void wxSizerItem::DeleteWindows()
468{
50c06297 469 switch ( m_kind )
77aa9abd 470 {
50c06297
VZ
471 case Item_None:
472 case Item_Spacer:
473 break;
474
475 case Item_Window:
caa2490c
RN
476 //We are deleting the window from this sizer - normally
477 //the window destroys the sizer associated with it,
478 //which might destroy this, which we don't want
479 m_window->SetContainingSizer(NULL);
50c06297 480 m_window->Destroy();
caa2490c
RN
481 //Putting this after the switch will result in a spacer
482 //not being deleted properly on destruction
902725ee 483 m_kind = Item_None;
50c06297
VZ
484 break;
485
486 case Item_Sizer:
487 m_sizer->DeleteWindows();
488 break;
489
490 case Item_Max:
491 default:
492 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
77aa9abd 493 }
be90c029 494
84f7908b
RR
495}
496
50c06297 497void wxSizerItem::Show( bool show )
5279a24d 498{
50c06297
VZ
499 switch ( m_kind )
500 {
501 case Item_None:
502 wxFAIL_MSG( _T("can't show uninitialized sizer item") );
503 break;
5279a24d 504
50c06297
VZ
505 case Item_Window:
506 m_window->Show(show);
507 break;
5279a24d 508
50c06297 509 case Item_Sizer:
3a5910cb 510 m_sizer->Show(show);
50c06297
VZ
511 break;
512
513 case Item_Spacer:
514 m_spacer->Show(show);
515 break;
516
517 case Item_Max:
518 default:
519 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
520 }
5279a24d
RR
521}
522
50c06297 523bool wxSizerItem::IsShown() const
12a3f227 524{
50c06297
VZ
525 switch ( m_kind )
526 {
527 case Item_None:
f1662177
VZ
528 // we may be called from CalcMin(), just return false so that we're
529 // not used
50c06297
VZ
530 break;
531
532 case Item_Window:
533 return m_window->IsShown();
12a3f227 534
50c06297 535 case Item_Sizer:
f303d69f
VZ
536 // arbitrarily decide that if at least one of our elements is
537 // shown, so are we (this arbitrariness is the reason for
538 // deprecating this function)
539 {
29392c81
JS
540 // Some apps (such as dialog editors) depend on an empty sizer still
541 // being laid out correctly and reporting the correct size and position.
542 if (m_sizer->GetChildren().GetCount() == 0)
543 return true;
544
f303d69f
VZ
545 for ( wxSizerItemList::compatibility_iterator
546 node = m_sizer->GetChildren().GetFirst();
547 node;
548 node = node->GetNext() )
549 {
550 if ( node->GetData()->IsShown() )
551 return true;
552 }
553 }
554 return false;
12a3f227 555
50c06297
VZ
556 case Item_Spacer:
557 return m_spacer->IsShown();
558
559 case Item_Max:
560 default:
561 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
562 }
563
564 return false;
12a3f227
RL
565}
566
ca3e85cf 567#if WXWIN_COMPATIBILITY_2_6
12a3f227
RL
568void wxSizerItem::SetOption( int option )
569{
570 SetProportion( option );
571}
572
573int wxSizerItem::GetOption() const
574{
575 return GetProportion();
576}
ca3e85cf 577#endif // WXWIN_COMPATIBILITY_2_6
12a3f227
RL
578
579
5279a24d 580//---------------------------------------------------------------------------
3417c2cd 581// wxSizer
5279a24d
RR
582//---------------------------------------------------------------------------
583
3417c2cd 584wxSizer::~wxSizer()
5279a24d 585{
222ed1d6 586 WX_CLEAR_LIST(wxSizerItemList, m_children);
5279a24d 587}
0c0d686f 588
56eee37f 589wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
12a3f227
RL
590{
591 m_children.Insert( index, item );
0c0d686f 592
50c06297 593 if ( item->GetWindow() )
12a3f227 594 item->GetWindow()->SetContainingSizer( this );
56eee37f 595
e6cfcc0d
JS
596 if ( item->GetSizer() )
597 item->GetSizer()->SetContainingWindow( m_containingWindow );
598
56eee37f 599 return item;
12a3f227
RL
600}
601
e8cfff87
VZ
602void wxSizer::SetContainingWindow(wxWindow *win)
603{
604 if ( win == m_containingWindow )
605 return;
606
607 m_containingWindow = win;
608
609 // set the same window for all nested sizers as well, they also are in the
610 // same window
611 for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
612 node;
613 node = node->GetNext() )
614 {
615 wxSizerItem *const item = node->GetData();
616 wxSizer *const sizer = item->GetSizer();
617
618 if ( sizer )
619 {
620 sizer->SetContainingWindow(win);
621 }
622 }
623}
624
ca3e85cf 625#if WXWIN_COMPATIBILITY_2_6
12a3f227
RL
626bool wxSizer::Remove( wxWindow *window )
627{
628 return Detach( window );
42b4e99e 629}
ca3e85cf 630#endif // WXWIN_COMPATIBILITY_2_6
42b4e99e
RR
631
632bool wxSizer::Remove( wxSizer *sizer )
633{
12a3f227 634 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
0c0d686f 635
222ed1d6 636 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
42b4e99e
RR
637 while (node)
638 {
12a3f227
RL
639 wxSizerItem *item = node->GetData();
640
3ca6a5f0 641 if (item->GetSizer() == sizer)
222ed1d6
MB
642 {
643 delete item;
644 m_children.Erase( node );
645 return true;
646 }
12a3f227
RL
647
648 node = node->GetNext();
42b4e99e 649 }
0c0d686f 650
e0d8fb45 651 return false;
42b4e99e
RR
652}
653
e0d8fb45 654bool wxSizer::Remove( int index )
42b4e99e 655{
e0d8fb45
VZ
656 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
657 false,
12a3f227 658 _T("Remove index is out of range") );
0c0d686f 659
222ed1d6 660 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
0c0d686f 661
e0d8fb45 662 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227 663
a50cf60e 664 delete node->GetData();
222ed1d6 665 m_children.Erase( node );
a50cf60e 666
222ed1d6 667 return true;
42b4e99e 668}
0c0d686f 669
00976fe5
RL
670bool wxSizer::Detach( wxSizer *sizer )
671{
12a3f227 672 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
00976fe5 673
222ed1d6 674 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
00976fe5
RL
675 while (node)
676 {
12a3f227
RL
677 wxSizerItem *item = node->GetData();
678
00976fe5
RL
679 if (item->GetSizer() == sizer)
680 {
96fdbb60 681 item->DetachSizer();
89c20ac1 682 delete item;
222ed1d6
MB
683 m_children.Erase( node );
684 return true;
12a3f227
RL
685 }
686 node = node->GetNext();
687 }
688
e0d8fb45 689 return false;
12a3f227
RL
690}
691
692bool wxSizer::Detach( wxWindow *window )
693{
694 wxASSERT_MSG( window, _T("Detaching NULL window") );
695
222ed1d6 696 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
697 while (node)
698 {
699 wxSizerItem *item = node->GetData();
700
701 if (item->GetWindow() == window)
702 {
89c20ac1 703 delete item;
222ed1d6
MB
704 m_children.Erase( node );
705 return true;
00976fe5 706 }
12a3f227 707 node = node->GetNext();
00976fe5
RL
708 }
709
e0d8fb45 710 return false;
00976fe5
RL
711}
712
e0d8fb45 713bool wxSizer::Detach( int index )
00976fe5 714{
e0d8fb45
VZ
715 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
716 false,
12a3f227
RL
717 _T("Detach index is out of range") );
718
222ed1d6 719 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
00976fe5 720
e0d8fb45 721 wxCHECK_MSG( node, false, _T("Failed to find child node") );
00976fe5 722
e0d8fb45 723 wxSizerItem *item = node->GetData();
9cbee2ce 724
50c06297 725 if ( item->IsSizer() )
9cbee2ce 726 item->DetachSizer();
12a3f227 727
89c20ac1 728 delete item;
222ed1d6
MB
729 m_children.Erase( node );
730 return true;
00976fe5
RL
731}
732
eae0338f
RR
733bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
734{
735 wxASSERT_MSG( oldwin, _T("Replacing NULL window") );
736 wxASSERT_MSG( newwin, _T("Replacing with NULL window") );
737
738 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
739 while (node)
740 {
741 wxSizerItem *item = node->GetData();
742
743 if (item->GetWindow() == oldwin)
744 {
a50cf60e 745 item->AssignWindow(newwin);
eae0338f
RR
746 newwin->SetContainingSizer( this );
747 return true;
748 }
749 else if (recursive && item->IsSizer())
750 {
751 if (item->GetSizer()->Replace( oldwin, newwin, true ))
752 return true;
753 }
e8cfff87 754
eae0338f
RR
755 node = node->GetNext();
756 }
757
758 return false;
759}
760
761bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive )
762{
763 wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") );
764 wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") );
765
766 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
767 while (node)
768 {
769 wxSizerItem *item = node->GetData();
770
771 if (item->GetSizer() == oldsz)
772 {
a50cf60e 773 item->AssignSizer(newsz);
eae0338f
RR
774 return true;
775 }
776 else if (recursive && item->IsSizer())
777 {
778 if (item->GetSizer()->Replace( oldsz, newsz, true ))
779 return true;
e8cfff87
VZ
780 }
781
eae0338f
RR
782 node = node->GetNext();
783 }
784
785 return false;
786}
787
788bool wxSizer::Replace( size_t old, wxSizerItem *newitem )
789{
790 wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") );
791 wxASSERT_MSG( newitem, _T("Replacing with NULL item") );
792
793 wxSizerItemList::compatibility_iterator node = m_children.Item( old );
794
795 wxCHECK_MSG( node, false, _T("Failed to find child node") );
796
797 wxSizerItem *item = node->GetData();
798 node->SetData(newitem);
e8cfff87 799 delete item;
eae0338f
RR
800
801 return true;
802}
803
84f7908b
RR
804void wxSizer::Clear( bool delete_windows )
805{
be90c029 806 // First clear the ContainingSizer pointers
222ed1d6 807 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
be90c029
RD
808 while (node)
809 {
12a3f227
RL
810 wxSizerItem *item = node->GetData();
811
be90c029 812 if (item->IsWindow())
12a3f227
RL
813 item->GetWindow()->SetContainingSizer( NULL );
814 node = node->GetNext();
be90c029
RD
815 }
816
817 // Destroy the windows if needed
84f7908b
RR
818 if (delete_windows)
819 DeleteWindows();
be90c029
RD
820
821 // Now empty the list
222ed1d6 822 WX_CLEAR_LIST(wxSizerItemList, m_children);
84f7908b
RR
823}
824
825void wxSizer::DeleteWindows()
826{
222ed1d6 827 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
84f7908b
RR
828 while (node)
829 {
12a3f227
RL
830 wxSizerItem *item = node->GetData();
831
84f7908b 832 item->DeleteWindows();
12a3f227 833 node = node->GetNext();
84f7908b
RR
834 }
835}
836
e5251d4f 837wxSize wxSizer::Fit( wxWindow *window )
5279a24d 838{
98018a4b 839 // take the min size by default and limit it by max size
02dc0099 840 wxSize size = GetMinClientSize(window);
7e7bc14b 841 wxSize sizeMax;
98018a4b
VZ
842
843 wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
844 if ( tlw )
845 {
846 // hack for small screen devices where TLWs are always full screen
847 if ( tlw->IsAlwaysMaximized() )
848 {
c30199bf
RR
849 // do nothing
850 return tlw->GetSize();
98018a4b 851 }
7e7bc14b 852
c30199bf
RR
853 // limit the window to the size of the display it is on
854 int disp = wxDisplay::GetFromWindow(window);
855 if ( disp == wxNOT_FOUND )
98018a4b 856 {
c30199bf
RR
857 // or, if we don't know which one it is, of the main one
858 disp = 0;
98018a4b 859 }
9ef2e675 860
7e7bc14b
VS
861 sizeMax = wxDisplay(disp).GetClientArea().GetSize();
862
c30199bf 863 // space for decorations and toolbars etc.
77fe7204 864 sizeMax = tlw->WindowToClientSize(sizeMax);
c30199bf
RR
865 }
866 else
867 {
7e7bc14b 868 sizeMax = GetMaxClientSize(window);
c30199bf 869 }
7e7bc14b
VS
870
871 if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
872 size.x = sizeMax.x;
873 if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
874 size.y = sizeMax.y;
875
876 // set client size
877 window->SetClientSize( size );
878
879 // return entire size
880 return window->GetSize();
5279a24d
RR
881}
882
566d84a7
RL
883void wxSizer::FitInside( wxWindow *window )
884{
885 wxSize size;
886 if (window->IsTopLevel())
887 size = VirtualFitSize( window );
888 else
889 size = GetMinClientSize( window );
890
891 window->SetVirtualSize( size );
892}
893
3417c2cd 894void wxSizer::Layout()
c62ac5b6 895{
ba763a45
RD
896 // (re)calculates minimums needed for each item and other preparations
897 // for layout
42b4e99e 898 CalcMin();
ba763a45
RD
899
900 // Applies the layout and repositions/resizes the items
c62ac5b6
RR
901 RecalcSizes();
902}
903
3417c2cd 904void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 905{
34c3ffca
RL
906 // Preserve the window's max size hints, but set the
907 // lower bound according to the sizer calculations.
908
e5251d4f
VZ
909 wxSize size = Fit( window );
910
34c3ffca
RL
911 window->SetSizeHints( size.x,
912 size.y,
913 window->GetMaxWidth(),
914 window->GetMaxHeight() );
5279a24d
RR
915}
916
f944aec0 917#if WXWIN_COMPATIBILITY_2_8
566d84a7
RL
918void wxSizer::SetVirtualSizeHints( wxWindow *window )
919{
566d84a7 920 FitInside( window );
566d84a7 921}
f944aec0 922#endif // WXWIN_COMPATIBILITY_2_8
566d84a7 923
9cbee2ce 924wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
65ba4113 925{
34c3ffca 926 return window->GetMaxSize();
65ba4113
GT
927}
928
3417c2cd 929wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 930{
77fe7204 931 return window->ClientToWindowSize(GetMinSize());
5279a24d
RR
932}
933
e11d436b
SC
934// TODO on mac we need a function that determines how much free space this
935// min size contains, in order to make sure that we have 20 pixels of free
936// space around the controls
9cbee2ce 937wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7 938{
77fe7204 939 return window->WindowToClientSize(window->GetMaxSize());
566d84a7
RL
940}
941
1b0674f7 942wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
943{
944 return GetMinSize(); // Already returns client size.
945}
946
947wxSize wxSizer::VirtualFitSize( wxWindow *window )
948{
949 wxSize size = GetMinClientSize( window );
950 wxSize sizeMax = GetMaxClientSize( window );
951
952 // Limit the size if sizeMax != wxDefaultSize
953
d775fa82 954 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
566d84a7 955 size.x = sizeMax.x;
d775fa82 956 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
566d84a7
RL
957 size.y = sizeMax.y;
958
959 return size;
960}
961
3417c2cd 962void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
963{
964 m_position.x = x;
965 m_position.y = y;
966 m_size.x = width;
967 m_size.y = height;
2b5f62a0 968 Layout();
5279a24d
RR
969}
970
f6bcfd97 971wxSize wxSizer::GetMinSize()
3ca6a5f0 972{
f6bcfd97
BP
973 wxSize ret( CalcMin() );
974 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
975 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 976 return ret;
f6bcfd97
BP
977}
978
979void wxSizer::DoSetMinSize( int width, int height )
980{
981 m_minSize.x = width;
982 m_minSize.y = height;
983}
984
985bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
986{
12a3f227
RL
987 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
988
989 // Is it our immediate child?
f6bcfd97 990
222ed1d6 991 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
992 while (node)
993 {
12a3f227
RL
994 wxSizerItem *item = node->GetData();
995
3ca6a5f0
BP
996 if (item->GetWindow() == window)
997 {
1eba2193 998 item->SetMinSize( width, height );
e0d8fb45 999 return true;
3ca6a5f0 1000 }
12a3f227 1001 node = node->GetNext();
f6bcfd97
BP
1002 }
1003
12a3f227
RL
1004 // No? Search any subsizers we own then
1005
1006 node = m_children.GetFirst();
f6bcfd97
BP
1007 while (node)
1008 {
12a3f227
RL
1009 wxSizerItem *item = node->GetData();
1010
1011 if ( item->GetSizer() &&
1012 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 1013 {
12a3f227 1014 // A child sizer found the requested windw, exit.
e0d8fb45 1015 return true;
3ca6a5f0 1016 }
12a3f227 1017 node = node->GetNext();
f6bcfd97
BP
1018 }
1019
e0d8fb45 1020 return false;
f6bcfd97
BP
1021}
1022
1023bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
1024{
12a3f227 1025 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 1026
12a3f227
RL
1027 // Is it our immediate child?
1028
222ed1d6 1029 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1030 while (node)
1031 {
12a3f227
RL
1032 wxSizerItem *item = node->GetData();
1033
3ca6a5f0
BP
1034 if (item->GetSizer() == sizer)
1035 {
f6bcfd97 1036 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 1037 return true;
3ca6a5f0 1038 }
12a3f227 1039 node = node->GetNext();
f6bcfd97
BP
1040 }
1041
12a3f227
RL
1042 // No? Search any subsizers we own then
1043
1044 node = m_children.GetFirst();
f6bcfd97
BP
1045 while (node)
1046 {
12a3f227
RL
1047 wxSizerItem *item = node->GetData();
1048
1049 if ( item->GetSizer() &&
1050 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 1051 {
12a3f227 1052 // A child found the requested sizer, exit.
e0d8fb45 1053 return true;
3ca6a5f0 1054 }
12a3f227 1055 node = node->GetNext();
f6bcfd97
BP
1056 }
1057
e0d8fb45 1058 return false;
f6bcfd97
BP
1059}
1060
12a3f227 1061bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 1062{
222ed1d6 1063 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
12a3f227 1064
e0d8fb45 1065 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
1066
1067 wxSizerItem *item = node->GetData();
f6bcfd97 1068
f6bcfd97
BP
1069 if (item->GetSizer())
1070 {
0ca5105b 1071 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
1072 item->GetSizer()->DoSetMinSize( width, height );
1073 }
1074 else
1075 {
ba763a45 1076 // ... but the minimal size of spacers and windows is stored via the item
1eba2193 1077 item->SetMinSize( width, height );
f6bcfd97
BP
1078 }
1079
e0d8fb45 1080 return true;
f6bcfd97
BP
1081}
1082
9f13661f 1083wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
2b5f62a0 1084{
9f13661f 1085 wxASSERT_MSG( window, _T("GetItem for NULL window") );
12a3f227 1086
222ed1d6 1087 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1088 while (node)
1089 {
12a3f227 1090 wxSizerItem *item = node->GetData();
2b5f62a0 1091
12a3f227 1092 if (item->GetWindow() == window)
2b5f62a0 1093 {
9f13661f 1094 return item;
2b5f62a0 1095 }
8b2bac62
WS
1096 else if (recursive && item->IsSizer())
1097 {
9f13661f
WS
1098 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
1099 if (subitem)
1100 return subitem;
8b2bac62
WS
1101 }
1102
12a3f227 1103 node = node->GetNext();
2b5f62a0 1104 }
8b2bac62 1105
9f13661f 1106 return NULL;
2b5f62a0
VZ
1107}
1108
9f13661f 1109wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
2b5f62a0 1110{
9f13661f 1111 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
12a3f227 1112
222ed1d6 1113 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1114 while (node)
1115 {
9f13661f 1116 wxSizerItem *item = node->GetData();
2b5f62a0 1117
12a3f227 1118 if (item->GetSizer() == sizer)
2b5f62a0 1119 {
9f13661f 1120 return item;
2b5f62a0 1121 }
8b2bac62
WS
1122 else if (recursive && item->IsSizer())
1123 {
9f13661f
WS
1124 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
1125 if (subitem)
1126 return subitem;
8b2bac62
WS
1127 }
1128
12a3f227 1129 node = node->GetNext();
2b5f62a0 1130 }
8b2bac62 1131
9f13661f
WS
1132 return NULL;
1133}
1134
1135wxSizerItem* wxSizer::GetItem( size_t index )
1136{
1137 wxCHECK_MSG( index < m_children.GetCount(),
1138 NULL,
1139 _T("GetItem index is out of range") );
1140
1141 return m_children.Item( index )->GetData();
1142}
1143
86909f4c
VZ
1144wxSizerItem* wxSizer::GetItemById( int id, bool recursive )
1145{
1146 // This gets a sizer item by the id of the sizer item
1147 // and NOT the id of a window if the item is a window.
1148
1149 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1150 while (node)
1151 {
1152 wxSizerItem *item = node->GetData();
1153
1154 if (item->GetId() == id)
1155 {
1156 return item;
1157 }
1158 else if (recursive && item->IsSizer())
1159 {
1160 wxSizerItem *subitem = item->GetSizer()->GetItemById( id, true );
1161 if (subitem)
1162 return subitem;
1163 }
1164
1165 node = node->GetNext();
1166 }
1167
1168 return NULL;
1169}
1170
9f13661f
WS
1171bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
1172{
1173 wxSizerItem *item = GetItem( window, recursive );
1174
1175 if ( item )
1176 {
1177 item->Show( show );
1178 return true;
1179 }
1180
1181 return false;
1182}
1183
1184bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
1185{
1186 wxSizerItem *item = GetItem( sizer, recursive );
1187
1188 if ( item )
1189 {
1190 item->Show( show );
1191 return true;
1192 }
1193
8b2bac62 1194 return false;
2b5f62a0
VZ
1195}
1196
8b2bac62 1197bool wxSizer::Show( size_t index, bool show)
2b5f62a0 1198{
9f13661f 1199 wxSizerItem *item = GetItem( index );
2b5f62a0 1200
9f13661f
WS
1201 if ( item )
1202 {
1203 item->Show( show );
1204 return true;
1205 }
8b2bac62 1206
9f13661f 1207 return false;
12a3f227 1208}
2b5f62a0 1209
12a3f227
RL
1210void wxSizer::ShowItems( bool show )
1211{
222ed1d6 1212 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
1213 while (node)
1214 {
1215 node->GetData()->Show( show );
1216 node = node->GetNext();
2b5f62a0
VZ
1217 }
1218}
1219
9cbee2ce 1220bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 1221{
222ed1d6 1222 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1223 while (node)
1224 {
12a3f227 1225 wxSizerItem *item = node->GetData();
dc259b79 1226
12a3f227 1227 if (item->GetWindow() == window)
2b5f62a0
VZ
1228 {
1229 return item->IsShown();
1230 }
12a3f227 1231 node = node->GetNext();
2b5f62a0
VZ
1232 }
1233
12a3f227
RL
1234 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1235
e0d8fb45 1236 return false;
2b5f62a0
VZ
1237}
1238
9cbee2ce 1239bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 1240{
222ed1d6 1241 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1242 while (node)
1243 {
12a3f227 1244 wxSizerItem *item = node->GetData();
2b5f62a0 1245
12a3f227 1246 if (item->GetSizer() == sizer)
2b5f62a0
VZ
1247 {
1248 return item->IsShown();
1249 }
12a3f227 1250 node = node->GetNext();
2b5f62a0
VZ
1251 }
1252
12a3f227
RL
1253 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1254
e0d8fb45 1255 return false;
2b5f62a0
VZ
1256}
1257
9cbee2ce 1258bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
1259{
1260 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 1261 false,
12a3f227
RL
1262 _T("IsShown index is out of range") );
1263
1264 return m_children.Item( index )->GetData()->IsShown();
1265}
1266
1267
f6bcfd97
BP
1268//---------------------------------------------------------------------------
1269// wxGridSizer
1270//---------------------------------------------------------------------------
1271
1272wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
902725ee 1273 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
12a3f227
RL
1274 , m_cols( cols )
1275 , m_vgap( vgap )
1276 , m_hgap( hgap )
f6bcfd97 1277{
f6bcfd97
BP
1278}
1279
1280wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
902725ee 1281 : m_rows( cols == 0 ? 1 : 0 )
12a3f227
RL
1282 , m_cols( cols )
1283 , m_vgap( vgap )
1284 , m_hgap( hgap )
f6bcfd97 1285{
f6bcfd97
BP
1286}
1287
0ca5105b 1288int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 1289{
f6bcfd97 1290 int nitems = m_children.GetCount();
2b5f62a0 1291 if ( nitems)
0ca5105b
VZ
1292 {
1293 if ( m_cols )
1294 {
1295 ncols = m_cols;
1296 nrows = (nitems + m_cols - 1) / m_cols;
1297 }
1298 else if ( m_rows )
1299 {
1300 ncols = (nitems + m_rows - 1) / m_rows;
1301 nrows = m_rows;
1302 }
1303 else // 0 columns, 0 rows?
1304 {
1305 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 1306
0ca5105b
VZ
1307 nrows = ncols = 0;
1308 }
1309 }
1310
1311 return nitems;
1312}
1313
1314void wxGridSizer::RecalcSizes()
1315{
1316 int nitems, nrows, ncols;
1317 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1318 return;
f6bcfd97
BP
1319
1320 wxSize sz( GetSize() );
1321 wxPoint pt( GetPosition() );
3ca6a5f0
BP
1322
1323 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1324 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
1325
1326 int x = pt.x;
1327 for (int c = 0; c < ncols; c++)
1328 {
1329 int y = pt.y;
1330 for (int r = 0; r < nrows; r++)
1331 {
1332 int i = r * ncols + c;
1333 if (i < nitems)
1334 {
222ed1d6 1335 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1336
1337 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 1338
12a3f227 1339 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1340 }
1341 y = y + h + m_vgap;
1342 }
1343 x = x + w + m_hgap;
1344 }
1345}
1346
1347wxSize wxGridSizer::CalcMin()
1348{
196be0f1
JS
1349 int nrows, ncols;
1350 if ( CalcRowsCols(nrows, ncols) == 0 )
b3f1734f 1351 return wxSize();
f6bcfd97 1352
4f469fb5 1353 // Find the max width and height for any component
f6bcfd97
BP
1354 int w = 0;
1355 int h = 0;
3ca6a5f0 1356
222ed1d6 1357 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1358 while (node)
1359 {
12a3f227
RL
1360 wxSizerItem *item = node->GetData();
1361 wxSize sz( item->CalcMin() );
1362
f6bcfd97
BP
1363 w = wxMax( w, sz.x );
1364 h = wxMax( h, sz.y );
3ca6a5f0 1365
12a3f227 1366 node = node->GetNext();
f6bcfd97 1367 }
3ca6a5f0 1368
3d2085a4 1369 // In case we have a nested sizer with a two step algo , give it
15f7c305
RR
1370 // a chance to adjust to that (we give it width component)
1371 node = m_children.GetFirst();
1372 bool didChangeMinSize = false;
1373 while (node)
1374 {
1375 wxSizerItem *item = node->GetData();
1376 didChangeMinSize |= item->InformFirstDirection( wxHORIZONTAL, w, -1 );
3d2085a4 1377
15f7c305
RR
1378 node = node->GetNext();
1379 }
3d2085a4 1380
15f7c305
RR
1381 // And redo iteration in case min size changed
1382 if( didChangeMinSize )
1383 {
1384 node = m_children.GetFirst();
1385 w = h = 0;
1386 while (node)
1387 {
1388 wxSizerItem *item = node->GetData();
1389 wxSize sz( item->GetMinSizeWithBorder() );
1390
1391 w = wxMax( w, sz.x );
1392 h = wxMax( h, sz.y );
1393
1394 node = node->GetNext();
3d2085a4 1395 }
15f7c305 1396 }
3d2085a4 1397
12a3f227
RL
1398 return wxSize( ncols * w + (ncols-1) * m_hgap,
1399 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
1400}
1401
1402void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1403{
1404 wxPoint pt( x,y );
8b2bac62 1405 wxSize sz( item->GetMinSizeWithBorder() );
f6bcfd97
BP
1406 int flag = item->GetFlag();
1407
1408 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1409 {
1410 sz = wxSize(w, h);
1411 }
1412 else
1413 {
1414 if (flag & wxALIGN_CENTER_HORIZONTAL)
1415 {
559b747d 1416 pt.x = x + (w - sz.x) / 2;
f6bcfd97
BP
1417 }
1418 else if (flag & wxALIGN_RIGHT)
1419 {
559b747d 1420 pt.x = x + (w - sz.x);
f6bcfd97 1421 }
3ca6a5f0 1422
f6bcfd97
BP
1423 if (flag & wxALIGN_CENTER_VERTICAL)
1424 {
559b747d 1425 pt.y = y + (h - sz.y) / 2;
f6bcfd97
BP
1426 }
1427 else if (flag & wxALIGN_BOTTOM)
1428 {
559b747d 1429 pt.y = y + (h - sz.y);
f6bcfd97
BP
1430 }
1431 }
3ca6a5f0 1432
f6bcfd97
BP
1433 item->SetDimension(pt, sz);
1434}
1435
1436//---------------------------------------------------------------------------
1437// wxFlexGridSizer
1438//---------------------------------------------------------------------------
1439
1440wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1441 : wxGridSizer( rows, cols, vgap, hgap ),
1442 m_flexDirection(wxBOTH),
1443 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1444{
f6bcfd97
BP
1445}
1446
1447wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1448 : wxGridSizer( cols, vgap, hgap ),
1449 m_flexDirection(wxBOTH),
1450 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1451{
f6bcfd97 1452}
3ca6a5f0 1453
f6bcfd97
BP
1454wxFlexGridSizer::~wxFlexGridSizer()
1455{
f6bcfd97
BP
1456}
1457
1458void wxFlexGridSizer::RecalcSizes()
1459{
74ab5f5b
VZ
1460 int nrows, ncols;
1461 if ( !CalcRowsCols(nrows, ncols) )
f6bcfd97
BP
1462 return;
1463
97800f66
VZ
1464 const wxPoint pt(GetPosition());
1465 const wxSize sz(GetSize());
3ca6a5f0 1466
97800f66 1467 AdjustForGrowables(sz);
f6bcfd97 1468
97800f66 1469 wxSizerItemList::const_iterator i = m_children.begin();
cc67d082
VZ
1470 const wxSizerItemList::const_iterator end = m_children.end();
1471
97800f66
VZ
1472 int y = 0;
1473 for ( int r = 0; r < nrows; r++ )
f6bcfd97 1474 {
97800f66 1475 if ( m_rowHeights[r] == -1 )
f6bcfd97 1476 {
97800f66
VZ
1477 // this row is entirely hidden, skip it
1478 for ( int c = 0; c < ncols; c++ )
cc67d082
VZ
1479 {
1480 if ( i == end )
1481 return;
1482
97800f66 1483 ++i;
cc67d082 1484 }
12a3f227 1485
97800f66
VZ
1486 continue;
1487 }
3ca6a5f0 1488
97800f66
VZ
1489 const int hrow = m_rowHeights[r];
1490 int h = sz.y - y; // max remaining height, don't overflow it
1491 if ( hrow < h )
1492 h = hrow;
3ca6a5f0 1493
97800f66 1494 int x = 0;
cc67d082 1495 for ( int c = 0; c < ncols && i != end; c++, ++i )
97800f66
VZ
1496 {
1497 const int wcol = m_colWidths[c];
1498
1499 if ( wcol == -1 )
1500 continue;
1501
97800f66
VZ
1502 int w = sz.x - x; // max possible value, ensure we don't overflow
1503 if ( wcol < w )
1504 w = wcol;
1505
1506 SetItemBounds(*i, pt.x + x, pt.y + y, w, h);
1507
1508 x += wcol + m_hgap;
f6bcfd97 1509 }
97800f66 1510
cc67d082
VZ
1511 if ( i == end )
1512 return;
1513
97800f66 1514 y += hrow + m_vgap;
f6bcfd97
BP
1515 }
1516}
1517
97800f66
VZ
1518// helper function used in CalcMin() to sum up the sizes of non-hidden items
1519static int SumArraySizes(const wxArrayInt& sizes, int gap)
1520{
1521 // Sum total minimum size, including gaps between rows/columns.
1522 // -1 is used as a magic number meaning empty row/column.
1523 int total = 0;
1524
1525 const size_t count = sizes.size();
1526 for ( size_t n = 0; n < count; n++ )
1527 {
1528 if ( sizes[n] != -1 )
1529 {
1530 if ( total )
1531 total += gap; // separate from the previous column
1532
1533 total += sizes[n];
1534 }
1535 }
1536
1537 return total;
1538}
1539
15f7c305 1540void wxFlexGridSizer::FindWidthsAndHeights(int nrows, int ncols)
f6bcfd97 1541{
97800f66 1542 // We have to recalculate the sizes in case the item minimum size has
395a82b1
VZ
1543 // changed since the previous layout, or the item has been hidden using
1544 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1545 // dimension of the row/column will be -1, indicating that the column
1546 // itself is hidden.
97800f66
VZ
1547 m_rowHeights.assign(nrows, -1);
1548 m_colWidths.assign(ncols, -1);
1549
1550 // n is the index of the item in left-to-right top-to-bottom order
1551 size_t n = 0;
1552 for ( wxSizerItemList::iterator i = m_children.begin();
1553 i != m_children.end();
1554 ++i, ++n )
f6bcfd97 1555 {
97800f66 1556 wxSizerItem * const item = *i;
55f9f0cb
VZ
1557 if ( item->IsShown() )
1558 {
3d2085a4 1559 // NOTE: Not doing the calculation here, this is just
15f7c305
RR
1560 // for finding max values.
1561 const wxSize sz(item->GetMinSizeWithBorder());
12a3f227 1562
97800f66
VZ
1563 const int row = n / ncols;
1564 const int col = n % ncols;
3ca6a5f0 1565
97800f66
VZ
1566 if ( sz.y > m_rowHeights[row] )
1567 m_rowHeights[row] = sz.y;
1568 if ( sz.x > m_colWidths[col] )
1569 m_colWidths[col] = sz.x;
1570 }
f6bcfd97 1571 }
3ca6a5f0 1572
20b35a69 1573 AdjustForFlexDirection();
8b2bac62 1574
97800f66
VZ
1575 m_calculatedMinSize = wxSize(SumArraySizes(m_colWidths, m_hgap),
1576 SumArraySizes(m_rowHeights, m_vgap));
15f7c305
RR
1577}
1578
1579wxSize wxFlexGridSizer::CalcMin()
1580{
1581 int nrows,
1582 ncols;
1583
1584 // Number of rows/columns can change as items are added or removed.
1585 if ( !CalcRowsCols(nrows, ncols) )
1586 return wxSize();
1587
1588
1589 // We have to recalculate the sizes in case the item minimum size has
1590 // changed since the previous layout, or the item has been hidden using
1591 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1592 // dimension of the row/column will be -1, indicating that the column
1593 // itself is hidden.
1594 m_rowHeights.assign(nrows, -1);
1595 m_colWidths.assign(ncols, -1);
1596
1597 // n is the index of the item in left-to-right top-to-bottom order
1598 size_t n = 0;
1599 for ( wxSizerItemList::iterator i = m_children.begin();
1600 i != m_children.end();
1601 ++i, ++n )
1602 {
1603 wxSizerItem * const item = *i;
1604 if ( item->IsShown() )
1605 {
1606 item->CalcMin();
1607 }
1608 }
1609
3d2085a4 1610 // The stage of looking for max values in each row/column has been
15f7c305
RR
1611 // made a separate function, since it's reused in AdjustForGrowables.
1612 FindWidthsAndHeights(nrows,ncols);
97800f66 1613
ba763a45 1614 return m_calculatedMinSize;
20b35a69
RD
1615}
1616
1617void wxFlexGridSizer::AdjustForFlexDirection()
1618{
1619 // the logic in CalcMin works when we resize flexibly in both directions
1620 // but maybe this is not the case
5d76f462
VZ
1621 if ( m_flexDirection != wxBOTH )
1622 {
1623 // select the array corresponding to the direction in which we do *not*
1624 // resize flexibly
1625 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1626 : m_rowHeights;
1627
4a10ea8b 1628 const size_t count = array.GetCount();
5d76f462
VZ
1629
1630 // find the largest value in this array
4a10ea8b
MW
1631 size_t n;
1632 int largest = 0;
1633
5d76f462
VZ
1634 for ( n = 0; n < count; ++n )
1635 {
1636 if ( array[n] > largest )
1637 largest = array[n];
1638 }
1639
1640 // and now fill it with the largest value
1641 for ( n = 0; n < count; ++n )
1642 {
b9a325a1
VZ
1643 // don't touch hidden rows
1644 if ( array[n] != -1 )
1645 array[n] = largest;
5d76f462
VZ
1646 }
1647 }
8b2bac62 1648}
5d76f462 1649
97800f66
VZ
1650// helper of AdjustForGrowables() which is called for rows/columns separately
1651//
1652// parameters:
1653// delta: the extra space, we do nothing unless it's positive
1654// growable: indices or growable rows/cols in sizes array
1655// sizes: the height/widths of rows/cols to adjust
1656// proportions: proportions of the growable rows/cols or NULL if they all
1657// should be assumed to have proportion of 1
1658static void
1659DoAdjustForGrowables(int delta,
1660 const wxArrayInt& growable,
1661 wxArrayInt& sizes,
1662 const wxArrayInt *proportions)
1663{
1664 if ( delta <= 0 )
1665 return;
3ca6a5f0 1666
97800f66
VZ
1667 // total sum of proportions of all non-hidden rows
1668 int sum_proportions = 0;
8b2bac62 1669
97800f66
VZ
1670 // number of currently shown growable rows
1671 int num = 0;
3ca6a5f0 1672
97800f66
VZ
1673 const int max_idx = sizes.size();
1674
1675 const size_t count = growable.size();
1676 size_t idx;
1677 for ( idx = 0; idx < count; idx++ )
20b35a69 1678 {
97800f66
VZ
1679 // Since the number of rows/columns can change as items are
1680 // inserted/deleted, we need to verify at runtime that the
1681 // requested growable rows/columns are still valid.
1682 if ( growable[idx] >= max_idx )
1683 continue;
1684
1685 // If all items in a row/column are hidden, that row/column will
1686 // have a dimension of -1. This causes the row/column to be
1687 // hidden completely.
1688 if ( sizes[growable[idx]] == -1 )
1689 continue;
1690
1691 if ( proportions )
1692 sum_proportions += (*proportions)[idx];
1693
1694 num++;
20b35a69
RD
1695 }
1696
97800f66
VZ
1697 if ( !num )
1698 return;
1699
1700 // the remaining extra free space, adjusted during each iteration
1701 for ( idx = 0; idx < count; idx++ )
20b35a69 1702 {
97800f66
VZ
1703 if ( growable[idx] >= max_idx )
1704 continue;
8b2bac62 1705
97800f66
VZ
1706 if ( sizes[ growable[idx] ] == -1 )
1707 continue;
20b35a69 1708
97800f66
VZ
1709 int cur_delta;
1710 if ( sum_proportions == 0 )
20b35a69 1711 {
97800f66
VZ
1712 // no growable rows -- divide extra space evenly among all
1713 cur_delta = delta/num;
1714 num--;
20b35a69 1715 }
97800f66
VZ
1716 else // allocate extra space proportionally
1717 {
1718 const int cur_prop = (*proportions)[idx];
1719 cur_delta = (delta*cur_prop)/sum_proportions;
1720 sum_proportions -= cur_prop;
1721 }
1722
1723 sizes[growable[idx]] += cur_delta;
1724 delta -= cur_delta;
20b35a69 1725 }
97800f66
VZ
1726}
1727
1728void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
1729{
15f7c305 1730 if ( (m_flexDirection & wxHORIZONTAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
97800f66 1731 {
97800f66
VZ
1732 DoAdjustForGrowables
1733 (
15f7c305
RR
1734 sz.x - m_calculatedMinSize.x,
1735 m_growableCols,
1736 m_colWidths,
1737 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
97800f66
VZ
1738 : NULL
1739 );
3d2085a4
VZ
1740
1741 // This gives nested objects that benefit from knowing one size
1742 // component in advance the chance to use that.
15f7c305
RR
1743 bool didAdjustMinSize = false;
1744 int nrows, ncols;
1745 CalcRowsCols(nrows, ncols);
3d2085a4 1746
15f7c305
RR
1747 // Iterate over all items and inform about column width
1748 size_t n = 0;
1749 for ( wxSizerItemList::iterator i = m_children.begin();
1750 i != m_children.end();
1751 ++i, ++n )
1752 {
1753 const int col = n % ncols;
1754 didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
97800f66
VZ
1755 }
1756
3d2085a4 1757 // Only redo if info was actually used
15f7c305 1758 if( didAdjustMinSize )
20b35a69 1759 {
97800f66
VZ
1760 DoAdjustForGrowables
1761 (
1762 sz.x - m_calculatedMinSize.x,
1763 m_growableCols,
1764 m_colWidths,
1765 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
1766 : NULL
1767 );
20b35a69 1768 }
f6bcfd97
BP
1769}
1770
15f7c305
RR
1771 if ( (m_flexDirection & wxVERTICAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
1772 {
1773 // pass NULL instead of proportions if the grow mode is ALL as we
1774 // should treat all rows as having proportion of 1 then
1775 DoAdjustForGrowables
1776 (
1777 sz.y - m_calculatedMinSize.y,
1778 m_growableRows,
1779 m_rowHeights,
1780 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableRowsProportions
1781 : NULL
1782 );
1783 }
1784}
1785
20b35a69 1786
e8800dcf 1787void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1788{
1789 m_growableRows.Add( idx );
e8800dcf 1790 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1791}
1792
e8800dcf 1793void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1794{
1795 m_growableCols.Add( idx );
e8800dcf 1796 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1797}
1798
ca243008
VZ
1799// helper function for RemoveGrowableCol/Row()
1800static void
1801DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1802{
1803 const size_t count = items.size();
1804 for ( size_t n = 0; n < count; n++ )
1805 {
1806 if ( (size_t)items[n] == idx )
1807 {
1808 items.RemoveAt(n);
1809 proportions.RemoveAt(n);
1810 return;
1811 }
1812 }
1813
1814 wxFAIL_MSG( _T("column/row is already not growable") );
1815}
1816
8d2474f4 1817void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
f6bcfd97 1818{
ca243008
VZ
1819 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1820}
1821
1822void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1823{
1824 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
f6bcfd97
BP
1825}
1826
c62ac5b6 1827//---------------------------------------------------------------------------
92afa2b1 1828// wxBoxSizer
61d514bb
RR
1829//---------------------------------------------------------------------------
1830
92afa2b1 1831void wxBoxSizer::RecalcSizes()
61d514bb 1832{
89064717 1833 if ( m_children.empty() )
61d514bb 1834 return;
0c0d686f 1835
3d2085a4 1836 const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
15f7c305 1837
89064717
VZ
1838 // the amount of free space which we should redistribute among the
1839 // stretchable items (i.e. those with non zero proportion)
3d2085a4
VZ
1840 int delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1841
0c0d686f 1842
15f7c305
RR
1843 // Inform child items about the size in minor direction, that can
1844 // change how much free space we have in major dir and how to distribute it.
1845 int majorMinSum = 0;
82287aae
CE
1846 wxSizerItemList::const_iterator i ;
1847 for ( i = m_children.begin();
15f7c305
RR
1848 i != m_children.end();
1849 ++i )
1850 {
1851 wxSizerItem * const item = *i;
1852
1853 if ( !item->IsShown() )
1854 continue;
1855
1856 wxSize szMinPrev = item->GetMinSizeWithBorder();
1857 item->InformFirstDirection(m_orient^wxBOTH,totalMinorSize,delta);
1858 wxSize szMin = item->GetMinSizeWithBorder();
3d2085a4 1859 int deltaChange = GetSizeInMajorDir(szMin-szMinPrev);
15f7c305
RR
1860 if( deltaChange )
1861 {
3d2085a4
VZ
1862 // Since we passed available space along to the item, it should not
1863 // take too much, so delta should not become negative.
1864 delta -= deltaChange;
15f7c305 1865 }
3d2085a4 1866 majorMinSum += GetSizeInMajorDir(item->GetMinSizeWithBorder());
15f7c305
RR
1867 }
1868 // And update our min size
1869 SizeInMajorDir(m_minSize) = majorMinSum;
1870
1871
1872 // might have a new delta now
3d2085a4
VZ
1873 delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1874
89064717
VZ
1875 // the position at which we put the next child
1876 wxPoint pt(m_position);
12a3f227 1877
7fca7a73 1878 int totalProportion = m_totalProportion;
82287aae 1879 for ( i = m_children.begin();
89064717
VZ
1880 i != m_children.end();
1881 ++i )
1882 {
1883 wxSizerItem * const item = *i;
2b5f62a0 1884
89064717
VZ
1885 if ( !item->IsShown() )
1886 continue;
3d2085a4
VZ
1887
1888 const wxSize sizeThis(item->GetMinSizeWithBorder());
2b5f62a0 1889
89064717 1890 // adjust the size in the major direction using the proportion
3d2085a4 1891 wxCoord majorSize = GetSizeInMajorDir(sizeThis);
7fca7a73
VZ
1892 const int propItem = item->GetProportion();
1893 if ( propItem )
89064717 1894 {
7fca7a73
VZ
1895 const int deltaItem = (delta * propItem) / totalProportion;
1896
1897 majorSize += deltaItem;
1898
1899 delta -= deltaItem;
1900 totalProportion -= propItem;
89064717 1901 }
2b5f62a0 1902
2b5f62a0 1903
89064717
VZ
1904 // apply the alignment in the minor direction
1905 wxPoint posChild(pt);
2b5f62a0 1906
3d2085a4 1907 wxCoord minorSize = GetSizeInMinorDir(sizeThis);
89064717
VZ
1908 const int flag = item->GetFlag();
1909 if ( flag & (wxEXPAND | wxSHAPED) )
1910 {
1911 minorSize = totalMinorSize;
1912 }
1913 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1914 {
1915 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1916 }
1917 // NB: wxCENTRE is used here only for backwards compatibility,
1918 // wxALIGN_CENTRE should be used in new code
1919 else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1920 {
1921 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1922 }
978af864 1923
2b5f62a0 1924
89064717
VZ
1925 // apply RTL adjustment for horizontal sizers:
1926 if ( !IsVertical() && m_containingWindow )
1927 {
1928 posChild.x = m_containingWindow->AdjustForLayoutDirection
1929 (
1930 posChild.x,
1931 majorSize,
1932 m_size.x
1933 );
3ca6a5f0
BP
1934 }
1935
89064717
VZ
1936 // finally set size of this child and advance to the next one
1937 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1938
1939 PosInMajorDir(pt) += majorSize;
61d514bb
RR
1940 }
1941}
1942
92afa2b1 1943wxSize wxBoxSizer::CalcMin()
61d514bb 1944{
89064717
VZ
1945 m_totalProportion = 0;
1946 m_minSize = wxSize(0, 0);
0c0d686f 1947
89064717
VZ
1948 // calculate the minimal sizes for all items and count sum of proportions
1949 for ( wxSizerItemList::const_iterator i = m_children.begin();
1950 i != m_children.end();
1951 ++i )
85e5cfc9 1952 {
89064717 1953 wxSizerItem * const item = *i;
12a3f227 1954
89064717
VZ
1955 if ( !item->IsShown() )
1956 continue;
12a3f227 1957
3d2085a4
VZ
1958 const wxSize sizeMinThis = item->CalcMin();
1959 SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis);
1960 if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) )
1961 SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis);
85e5cfc9 1962
89064717 1963 m_totalProportion += item->GetProportion();
61d514bb 1964 }
0c0d686f 1965
89064717 1966 return m_minSize;
61d514bb 1967}
27ea1d8a 1968
15f7c305
RR
1969//---------------------------------------------------------------------------
1970// wxWrapSizer
1971//---------------------------------------------------------------------------
1972
3d2085a4
VZ
1973#define wxDEFAULT_PROPORTION_LAST 1000000
1974
1975// User data to hold old proportion for last item on line
15f7c305
RR
1976// (which might be extended)
1977struct wxPropHolder : public wxObject
1978{
1979 wxPropHolder( ) : m_item(0), m_propOld(0) { }
1980 void Init( wxSizerItem *item, int propOld ) { m_item=item; m_propOld=propOld; }
3d2085a4 1981
15f7c305
RR
1982 wxSizerItem *m_item;
1983 int m_propOld;
1984};
1985
1986IMPLEMENT_DYNAMIC_CLASS(wxWrapSizer, wxBoxSizer);
1987
1988wxWrapSizer::wxWrapSizer( int orient, int flags )
3d2085a4
VZ
1989 : wxBoxSizer(orient),
1990 m_prim_size_last( -1 ),
15f7c305
RR
1991 m_rows(orient^wxBOTH),
1992 m_flags(flags)
1993{
1994}
1995
1996wxWrapSizer::~wxWrapSizer()
1997{
1998 // Have to clear grand child items so that they're not deleted twice
1999 for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- )
2000 {
2001 wxSizer *psz = m_rows.GetItem((size_t)ix)->GetSizer();
2002 wxSizerItemList &sl = psz->GetChildren();
2003 while( sl.GetLast() )
2004 sl.Erase( sl.GetLast() );
2005 }
2006}
2007
2008
2009bool wxWrapSizer::InformFirstDirection( int direction, int size, int WXUNUSED(availableOtherDir) )
2010{
2011 if( !direction )
2012 {
3d2085a4
VZ
2013 // Better to keep value, then CalcMin will work better
2014 //m_prim_size_last = -1;
15f7c305
RR
2015 return false;
2016 }
2017 if( direction==m_orient )
2018 {
2019 // The direction is same as our primary, so we can make use of it
3d2085a4 2020 m_prim_size_last = size;
15f7c305
RR
2021 return true;
2022 }
3d2085a4 2023 else
15f7c305
RR
2024 return false;
2025}
2026
2027
2028void wxWrapSizer::AdjustPropLastItem(wxSizer *psz, wxSizerItem *itemLast)
2029{
2030 wxSizerItem *psi = m_rows.GetItem(psz);
2031 wxASSERT(psi);
2032 wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
3d2085a4 2033 if ( !pph )
15f7c305 2034 psi->SetUserData( pph=new wxPropHolder );
3d2085a4 2035
15f7c305
RR
2036 pph->Init( itemLast, itemLast->GetProportion() );
2037 itemLast->SetProportion( wxDEFAULT_PROPORTION_LAST );
2038}
2039
2040void wxWrapSizer::RecalcSizes()
2041{
2042 wxASSERT( m_orient&wxBOTH );
2043 if (m_children.GetCount() == 0)
2044 return;
2045
3d2085a4
VZ
2046 // What we do here is to put our items into child box sizers,
2047 // as many of them as we have lines.
15f7c305
RR
2048
2049 // Empty all items in all rows in owned sizer.
3d2085a4 2050 // We have to access the list directly, since we don't want to
15f7c305
RR
2051 // destroy the wxSizerItems.
2052 for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- ){
3d2085a4
VZ
2053 wxSizerItem *psi = m_rows.GetItem( (size_t)ix );
2054
2055 // Restore proportion for last item on line (if item has not been deleted)
2056 wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
2057 if( pph && GetChildren().Find(pph->m_item) )
2058 pph->m_item->SetProportion(pph->m_propOld);
2059
15f7c305
RR
2060 wxSizer *psz = psi->GetSizer();
2061 wxASSERT( psz );
2062 wxSizerItemList &sl = psz->GetChildren();
2063 while( sl.GetLast() )
2064 sl.Erase( sl.GetLast() );
2065 }
3d2085a4 2066
15f7c305 2067 int lineSumMajor = 0;
3d2085a4
VZ
2068 int majorSize = GetSizeInMajorDir(m_size);
2069
15f7c305
RR
2070 // Make sure we have at least one child sizer
2071 m_n_line = 1;
3d2085a4 2072 if( !m_rows.GetChildren().GetCount() )
15f7c305 2073 m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
3d2085a4 2074
15f7c305
RR
2075 // The sizer where to insert items in
2076 wxSizer *psz = m_rows.GetItem((size_t)0)->GetSizer();
2077 wxASSERT( psz );
3d2085a4 2078
15f7c305
RR
2079 // Now put our child items into child sizers instead
2080 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2081 wxSizerItem *item = NULL, *itemLast=NULL;
2082 while (node)
2083 {
2084 item = node->GetData();
2085 if ( item->IsShown() )
2086 {
3d2085a4
VZ
2087 wxSize minSz = item->GetMinSize();
2088 int minSzMajor = GetSizeInMajorDir(minSz);
2089
15f7c305 2090 // More space on this line?
3d2085a4 2091 if( !lineSumMajor || lineSumMajor+minSzMajor<=majorSize )
15f7c305
RR
2092 {
2093 lineSumMajor += minSzMajor;
2094 }
2095 else
2096 {
2097 lineSumMajor = minSzMajor;
2098 // Get a new empty sizer to insert into
2099 if( (int)m_rows.GetChildren().GetCount()<=m_n_line )
2100 m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
3d2085a4
VZ
2101
2102 // If we have extend-last-on-each-line mode, then do so now
15f7c305
RR
2103 // Note: We must store old proportion value then.
2104 if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
3d2085a4
VZ
2105 AdjustPropLastItem(psz,itemLast);
2106
15f7c305
RR
2107 // The sizer where to insert items in
2108 psz = m_rows.GetItem(m_n_line++)->GetSizer();
2109 }
3d2085a4 2110 itemLast = item;
15f7c305 2111 psz->Add( item );
3d2085a4
VZ
2112 // If item is a window, it now has a pointer to the child sizer,
2113 // which is wrong. Set it to point to us.
15f7c305 2114 if( item->GetWindow() )
3d2085a4 2115 item->GetWindow()->SetContainingSizer( this );
15f7c305
RR
2116 }
2117 node = node->GetNext();
2118 }
2119
3d2085a4 2120 // If we have extend-last-on-each-line mode, then do so now
15f7c305
RR
2121 if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
2122 AdjustPropLastItem(psz,itemLast);
3d2085a4
VZ
2123
2124 // If we have more sizers than lines, remove them
15f7c305
RR
2125 while( (int)m_rows.GetChildren().GetCount()>m_n_line )
2126 m_rows.Remove( m_n_line );
2127
2128 // Now do layout on row sizer
2129 m_rows.SetDimension( m_position.x, m_position.y, m_size.x, m_size.y );
3d2085a4 2130
15f7c305 2131 // Remember this to next time (will be overridden by InformFirstDirection if used)
3d2085a4 2132 m_prim_size_last = GetSizeInMajorDir(m_size);
15f7c305
RR
2133}
2134
2135
2136wxSize wxWrapSizer::CalcMin()
2137{
2138 if (m_children.GetCount() == 0)
2139 return wxSize();
2140
2141 // Algorithm for calculating min size: (assuming horizontal orientation)
2142 // X: Max width of all members
3d2085a4 2143 // Y: Based on last X, calculate how many lines needed
15f7c305 2144 // First time around, assume all items fits on one line
3d2085a4 2145
15f7c305
RR
2146 int maxMajor = 0;
2147 int minorSum = 0;
2148 int lineMaxMinor = 0;
2149 int lineSumMajor = 0;
2150 m_n_line = 0;
3d2085a4 2151
15f7c305
RR
2152 // precalc item minsizes and fit on lines (preliminary)
2153 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2154 while (node)
2155 {
2156 wxSizerItem *item = node->GetData();
2157 if ( item->IsShown() )
2158 {
2159 wxSize minSz = item->CalcMin();
3d2085a4
VZ
2160 int szMajor = GetSizeInMajorDir(minSz);
2161 int szMinor = GetSizeInMinorDir(minSz);
15f7c305
RR
2162 if( szMajor>maxMajor ) maxMajor = szMajor;
2163 // More space on this line?
3d2085a4
VZ
2164 if( m_prim_size_last<0 || !lineSumMajor ||
2165 lineSumMajor+szMajor<=m_prim_size_last )
15f7c305
RR
2166 {
2167 lineSumMajor += szMajor;
3d2085a4 2168 if( szMinor>lineMaxMinor )
15f7c305
RR
2169 lineMaxMinor = szMinor;
2170 }
2171 else
2172 {
2173 minorSum += lineMaxMinor; // Add height of highest item on last line
2174 m_n_line++;
2175 lineMaxMinor = szMinor;
2176 lineSumMajor = szMajor;
2177 }
2178 }
2179 node = node->GetNext();
2180 }
2181 minorSum += lineMaxMinor; // Add height of highest item on last line
2182
3d2085a4
VZ
2183 m_minSize = SizeFromMajorMinor(maxMajor, minorSum);
2184 return m_minSize;
15f7c305
RR
2185}
2186
27ea1d8a
RR
2187//---------------------------------------------------------------------------
2188// wxStaticBoxSizer
2189//---------------------------------------------------------------------------
2190
1e6feb95
VZ
2191#if wxUSE_STATBOX
2192
27ea1d8a 2193wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
e978011a
VZ
2194 : wxBoxSizer( orient ),
2195 m_staticBox( box )
27ea1d8a 2196{
223d09f6 2197 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
e978011a
VZ
2198
2199 // do this so that our Detach() is called if the static box is destroyed
2200 // before we are
2201 m_staticBox->SetContainingSizer(this);
27ea1d8a 2202}
0c0d686f 2203
6c1635b5
VZ
2204wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
2205 : wxBoxSizer(orient),
2206 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
2207{
e978011a
VZ
2208 // same as above
2209 m_staticBox->SetContainingSizer(this);
6c1635b5
VZ
2210}
2211
649cfca1
VZ
2212wxStaticBoxSizer::~wxStaticBoxSizer()
2213{
2214 delete m_staticBox;
2215}
2216
12a3f227
RL
2217static void GetStaticBoxBorders( wxStaticBox *box,
2218 int *borderTop,
2219 int *borderOther)
84028727
VZ
2220{
2221 // this has to be done platform by platform as there is no way to
2222 // guess the thickness of a wxStaticBox border
5dd070c2 2223 box->GetBordersForSizer(borderTop, borderOther);
84028727
VZ
2224}
2225
27ea1d8a
RR
2226void wxStaticBoxSizer::RecalcSizes()
2227{
84028727
VZ
2228 int top_border, other_border;
2229 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
2230
2231 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 2232
27ea1d8a
RR
2233 wxPoint old_pos( m_position );
2234 m_position.x += other_border;
2235 m_position.y += top_border;
2236 wxSize old_size( m_size );
2237 m_size.x -= 2*other_border;
2238 m_size.y -= top_border + other_border;
0c0d686f 2239
27ea1d8a 2240 wxBoxSizer::RecalcSizes();
0c0d686f 2241
27ea1d8a
RR
2242 m_position = old_pos;
2243 m_size = old_size;
2244}
2245
2246wxSize wxStaticBoxSizer::CalcMin()
2247{
84028727
VZ
2248 int top_border, other_border;
2249 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 2250
27ea1d8a 2251 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 2252 ret.x += 2*other_border;
27ea1d8a 2253 ret.y += other_border + top_border;
0c0d686f 2254
27ea1d8a
RR
2255 return ret;
2256}
83edc0a5 2257
eb2a7883
VZ
2258void wxStaticBoxSizer::ShowItems( bool show )
2259{
2260 m_staticBox->Show( show );
2261 wxBoxSizer::ShowItems( show );
2262}
2263
e978011a
VZ
2264bool wxStaticBoxSizer::Detach( wxWindow *window )
2265{
2266 // avoid deleting m_staticBox in our dtor if it's being detached from the
2267 // sizer (which can happen because it's being already destroyed for
2268 // example)
2269 if ( window == m_staticBox )
2270 {
2271 m_staticBox = NULL;
2272 return true;
2273 }
2274
2275 return wxSizer::Detach( window );
2276}
2277
1e6feb95
VZ
2278#endif // wxUSE_STATBOX
2279
974c2a59
WS
2280#if wxUSE_BUTTON
2281
acf2ac37
RR
2282wxStdDialogButtonSizer::wxStdDialogButtonSizer()
2283 : wxBoxSizer(wxHORIZONTAL)
2284{
94f53923
JS
2285 // Vertical buttons with lots of space on either side
2286 // looks rubbish on WinCE, so let's not do this for now.
2287 // If we are going to use vertical buttons, we should
2288 // put the sizer to the right of other controls in the dialog,
2289 // and that's beyond the scope of this sizer.
2290#ifndef __WXWINCE__
acf2ac37 2291 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
974c2a59 2292 // If we have a PDA screen, put yes/no button over
acf2ac37
RR
2293 // all other buttons, otherwise on the left side.
2294 if (is_pda)
2295 m_orient = wxVERTICAL;
94f53923 2296#endif
974c2a59 2297
acf2ac37
RR
2298 m_buttonAffirmative = NULL;
2299 m_buttonApply = NULL;
2300 m_buttonNegative = NULL;
2301 m_buttonCancel = NULL;
2302 m_buttonHelp = NULL;
2303}
2304
2305void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
2306{
2307 switch (mybutton->GetId())
2308 {
2309 case wxID_OK:
2310 case wxID_YES:
2311 case wxID_SAVE:
2312 m_buttonAffirmative = mybutton;
2313 break;
2314 case wxID_APPLY:
2315 m_buttonApply = mybutton;
2316 break;
2317 case wxID_NO:
2318 m_buttonNegative = mybutton;
2319 break;
2320 case wxID_CANCEL:
57d7f988 2321 case wxID_CLOSE:
acf2ac37
RR
2322 m_buttonCancel = mybutton;
2323 break;
2324 case wxID_HELP:
2997ca30 2325 case wxID_CONTEXT_HELP:
acf2ac37
RR
2326 m_buttonHelp = mybutton;
2327 break;
2328 default:
2329 break;
2330 }
2331}
2332
b181a505
RR
2333void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
2334{
2335 m_buttonAffirmative = button;
2336}
2337
2338void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
2339{
2340 m_buttonNegative = button;
2341}
2342
2343void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
2344{
2345 m_buttonCancel = button;
2346}
2347
718903fe 2348void wxStdDialogButtonSizer::Realize()
acf2ac37
RR
2349{
2350#ifdef __WXMAC__
2351 Add(0, 0, 0, wxLEFT, 6);
2352 if (m_buttonHelp)
974c2a59
WS
2353 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2354
acf2ac37
RR
2355 if (m_buttonNegative){
2356 // HIG POLICE BULLETIN - destructive buttons need extra padding
2357 // 24 pixels on either side
2358 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
2359 }
974c2a59 2360
acf2ac37 2361 // extra whitespace between help/negative and cancel/ok buttons
974c2a59
WS
2362 Add(0, 0, 1, wxEXPAND, 0);
2363
acf2ac37
RR
2364 if (m_buttonCancel){
2365 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2366 // Cancel or help should be default
2367 // m_buttonCancel->SetDefaultButton();
2368 }
974c2a59
WS
2369
2370 // Ugh, Mac doesn't really have apply dialogs, so I'll just
acf2ac37
RR
2371 // figure the best place is between Cancel and OK
2372 if (m_buttonApply)
2373 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
974c2a59 2374
acf2ac37
RR
2375 if (m_buttonAffirmative){
2376 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
974c2a59 2377
acf2ac37
RR
2378 if (m_buttonAffirmative->GetId() == wxID_SAVE){
2379 // these buttons have set labels under Mac so we should use them
2380 m_buttonAffirmative->SetLabel(_("Save"));
d9485f89
RD
2381 if (m_buttonNegative)
2382 m_buttonNegative->SetLabel(_("Don't Save"));
acf2ac37
RR
2383 }
2384 }
974c2a59 2385
acf2ac37
RR
2386 // Extra space around and at the right
2387 Add(12, 24);
2388#elif defined(__WXGTK20__)
2389 Add(0, 0, 0, wxLEFT, 9);
2390 if (m_buttonHelp)
974c2a59
WS
2391 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2392
acf2ac37 2393 // extra whitespace between help and cancel/ok buttons
974c2a59
WS
2394 Add(0, 0, 1, wxEXPAND, 0);
2395
acf2ac37
RR
2396 if (m_buttonNegative){
2397 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2398 }
974c2a59 2399
e6cfcc0d 2400 // according to HIG, in explicit apply windows the order is:
57d7f988
VZ
2401 // [ Help Apply Cancel OK ]
2402 if (m_buttonApply)
2403 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2404
acf2ac37
RR
2405 if (m_buttonCancel){
2406 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2407 // Cancel or help should be default
2408 // m_buttonCancel->SetDefaultButton();
2409 }
974c2a59 2410
acf2ac37
RR
2411 if (m_buttonAffirmative)
2412 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
0f884515
JS
2413#elif defined(__WXMSW__)
2414 // Windows
2415
2416 // right-justify buttons
2417 Add(0, 0, 1, wxEXPAND, 0);
2418
2419 if (m_buttonAffirmative){
2420 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2421 }
2422
2423 if (m_buttonNegative){
2424 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2425 }
2426
2427 if (m_buttonCancel){
2428 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2429 }
2430 if (m_buttonApply)
2431 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2432
2433 if (m_buttonHelp)
2434 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
acf2ac37 2435#else
0f884515 2436 // GTK+1 and any other platform
902725ee 2437
23b1018f 2438 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
acf2ac37 2439 if (m_buttonHelp)
974c2a59
WS
2440 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2441
acf2ac37 2442 // extra whitespace between help and cancel/ok buttons
974c2a59 2443 Add(0, 0, 1, wxEXPAND, 0);
acf2ac37
RR
2444
2445 if (m_buttonApply)
2446 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
974c2a59 2447
acf2ac37
RR
2448 if (m_buttonAffirmative){
2449 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2450 }
974c2a59 2451
acf2ac37
RR
2452 if (m_buttonNegative){
2453 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2454 }
974c2a59 2455
acf2ac37 2456 if (m_buttonCancel){
23b1018f 2457 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
acf2ac37
RR
2458 // Cancel or help should be default
2459 // m_buttonCancel->SetDefaultButton();
2460 }
974c2a59 2461
acf2ac37
RR
2462#endif
2463}
adbf2d73 2464
974c2a59 2465#endif // wxUSE_BUTTON