]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
Fix tracking rectangles in 64-bit build by remembering the tag as the 64-bit integer...
[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
RR
863 // space for decorations and toolbars etc.
864 wxSize tlw_client_size = tlw->GetClientSize();
865 wxSize tlw_size = tlw->GetSize();
866 sizeMax.x -= tlw_size.x - tlw_client_size.x;
867 sizeMax.y -= tlw_size.y - tlw_client_size.y;
c30199bf
RR
868 }
869 else
870 {
7e7bc14b 871 sizeMax = GetMaxClientSize(window);
c30199bf 872 }
7e7bc14b
VS
873
874 if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
875 size.x = sizeMax.x;
876 if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
877 size.y = sizeMax.y;
878
879 // set client size
880 window->SetClientSize( size );
881
882 // return entire size
883 return window->GetSize();
5279a24d
RR
884}
885
566d84a7
RL
886void wxSizer::FitInside( wxWindow *window )
887{
888 wxSize size;
889 if (window->IsTopLevel())
890 size = VirtualFitSize( window );
891 else
892 size = GetMinClientSize( window );
893
894 window->SetVirtualSize( size );
895}
896
3417c2cd 897void wxSizer::Layout()
c62ac5b6 898{
ba763a45
RD
899 // (re)calculates minimums needed for each item and other preparations
900 // for layout
42b4e99e 901 CalcMin();
ba763a45
RD
902
903 // Applies the layout and repositions/resizes the items
c62ac5b6
RR
904 RecalcSizes();
905}
906
3417c2cd 907void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 908{
34c3ffca
RL
909 // Preserve the window's max size hints, but set the
910 // lower bound according to the sizer calculations.
911
e5251d4f
VZ
912 wxSize size = Fit( window );
913
34c3ffca
RL
914 window->SetSizeHints( size.x,
915 size.y,
916 window->GetMaxWidth(),
917 window->GetMaxHeight() );
5279a24d
RR
918}
919
f944aec0 920#if WXWIN_COMPATIBILITY_2_8
566d84a7
RL
921void wxSizer::SetVirtualSizeHints( wxWindow *window )
922{
566d84a7 923 FitInside( window );
566d84a7 924}
f944aec0 925#endif // WXWIN_COMPATIBILITY_2_8
566d84a7 926
9cbee2ce 927wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
65ba4113 928{
34c3ffca 929 return window->GetMaxSize();
65ba4113
GT
930}
931
3417c2cd 932wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 933{
12a3f227
RL
934 wxSize minSize( GetMinSize() );
935 wxSize size( window->GetSize() );
936 wxSize client_size( window->GetClientSize() );
937
77671fd2 938 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 939 minSize.y+size.y-client_size.y );
5279a24d
RR
940}
941
e11d436b
SC
942// TODO on mac we need a function that determines how much free space this
943// min size contains, in order to make sure that we have 20 pixels of free
944// space around the controls
9cbee2ce 945wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7
RL
946{
947 wxSize maxSize( window->GetMaxSize() );
948
50c06297 949 if ( maxSize != wxDefaultSize )
566d84a7
RL
950 {
951 wxSize size( window->GetSize() );
952 wxSize client_size( window->GetClientSize() );
953
954 return wxSize( maxSize.x + client_size.x - size.x,
955 maxSize.y + client_size.y - size.y );
956 }
957 else
958 return wxDefaultSize;
959}
960
1b0674f7 961wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
962{
963 return GetMinSize(); // Already returns client size.
964}
965
966wxSize wxSizer::VirtualFitSize( wxWindow *window )
967{
968 wxSize size = GetMinClientSize( window );
969 wxSize sizeMax = GetMaxClientSize( window );
970
971 // Limit the size if sizeMax != wxDefaultSize
972
d775fa82 973 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
566d84a7 974 size.x = sizeMax.x;
d775fa82 975 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
566d84a7
RL
976 size.y = sizeMax.y;
977
978 return size;
979}
980
3417c2cd 981void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
982{
983 m_position.x = x;
984 m_position.y = y;
985 m_size.x = width;
986 m_size.y = height;
2b5f62a0 987 Layout();
5279a24d
RR
988}
989
f6bcfd97 990wxSize wxSizer::GetMinSize()
3ca6a5f0 991{
f6bcfd97
BP
992 wxSize ret( CalcMin() );
993 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
994 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 995 return ret;
f6bcfd97
BP
996}
997
998void wxSizer::DoSetMinSize( int width, int height )
999{
1000 m_minSize.x = width;
1001 m_minSize.y = height;
1002}
1003
1004bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
1005{
12a3f227
RL
1006 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
1007
1008 // Is it our immediate child?
f6bcfd97 1009
222ed1d6 1010 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1011 while (node)
1012 {
12a3f227
RL
1013 wxSizerItem *item = node->GetData();
1014
3ca6a5f0
BP
1015 if (item->GetWindow() == window)
1016 {
1eba2193 1017 item->SetMinSize( width, height );
e0d8fb45 1018 return true;
3ca6a5f0 1019 }
12a3f227 1020 node = node->GetNext();
f6bcfd97
BP
1021 }
1022
12a3f227
RL
1023 // No? Search any subsizers we own then
1024
1025 node = m_children.GetFirst();
f6bcfd97
BP
1026 while (node)
1027 {
12a3f227
RL
1028 wxSizerItem *item = node->GetData();
1029
1030 if ( item->GetSizer() &&
1031 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 1032 {
12a3f227 1033 // A child sizer found the requested windw, exit.
e0d8fb45 1034 return true;
3ca6a5f0 1035 }
12a3f227 1036 node = node->GetNext();
f6bcfd97
BP
1037 }
1038
e0d8fb45 1039 return false;
f6bcfd97
BP
1040}
1041
1042bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
1043{
12a3f227 1044 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 1045
12a3f227
RL
1046 // Is it our immediate child?
1047
222ed1d6 1048 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1049 while (node)
1050 {
12a3f227
RL
1051 wxSizerItem *item = node->GetData();
1052
3ca6a5f0
BP
1053 if (item->GetSizer() == sizer)
1054 {
f6bcfd97 1055 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 1056 return true;
3ca6a5f0 1057 }
12a3f227 1058 node = node->GetNext();
f6bcfd97
BP
1059 }
1060
12a3f227
RL
1061 // No? Search any subsizers we own then
1062
1063 node = m_children.GetFirst();
f6bcfd97
BP
1064 while (node)
1065 {
12a3f227
RL
1066 wxSizerItem *item = node->GetData();
1067
1068 if ( item->GetSizer() &&
1069 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 1070 {
12a3f227 1071 // A child found the requested sizer, exit.
e0d8fb45 1072 return true;
3ca6a5f0 1073 }
12a3f227 1074 node = node->GetNext();
f6bcfd97
BP
1075 }
1076
e0d8fb45 1077 return false;
f6bcfd97
BP
1078}
1079
12a3f227 1080bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 1081{
222ed1d6 1082 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
12a3f227 1083
e0d8fb45 1084 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
1085
1086 wxSizerItem *item = node->GetData();
f6bcfd97 1087
f6bcfd97
BP
1088 if (item->GetSizer())
1089 {
0ca5105b 1090 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
1091 item->GetSizer()->DoSetMinSize( width, height );
1092 }
1093 else
1094 {
ba763a45 1095 // ... but the minimal size of spacers and windows is stored via the item
1eba2193 1096 item->SetMinSize( width, height );
f6bcfd97
BP
1097 }
1098
e0d8fb45 1099 return true;
f6bcfd97
BP
1100}
1101
9f13661f 1102wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
2b5f62a0 1103{
9f13661f 1104 wxASSERT_MSG( window, _T("GetItem for NULL window") );
12a3f227 1105
222ed1d6 1106 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1107 while (node)
1108 {
12a3f227 1109 wxSizerItem *item = node->GetData();
2b5f62a0 1110
12a3f227 1111 if (item->GetWindow() == window)
2b5f62a0 1112 {
9f13661f 1113 return item;
2b5f62a0 1114 }
8b2bac62
WS
1115 else if (recursive && item->IsSizer())
1116 {
9f13661f
WS
1117 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
1118 if (subitem)
1119 return subitem;
8b2bac62
WS
1120 }
1121
12a3f227 1122 node = node->GetNext();
2b5f62a0 1123 }
8b2bac62 1124
9f13661f 1125 return NULL;
2b5f62a0
VZ
1126}
1127
9f13661f 1128wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
2b5f62a0 1129{
9f13661f 1130 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
12a3f227 1131
222ed1d6 1132 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1133 while (node)
1134 {
9f13661f 1135 wxSizerItem *item = node->GetData();
2b5f62a0 1136
12a3f227 1137 if (item->GetSizer() == sizer)
2b5f62a0 1138 {
9f13661f 1139 return item;
2b5f62a0 1140 }
8b2bac62
WS
1141 else if (recursive && item->IsSizer())
1142 {
9f13661f
WS
1143 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
1144 if (subitem)
1145 return subitem;
8b2bac62
WS
1146 }
1147
12a3f227 1148 node = node->GetNext();
2b5f62a0 1149 }
8b2bac62 1150
9f13661f
WS
1151 return NULL;
1152}
1153
1154wxSizerItem* wxSizer::GetItem( size_t index )
1155{
1156 wxCHECK_MSG( index < m_children.GetCount(),
1157 NULL,
1158 _T("GetItem index is out of range") );
1159
1160 return m_children.Item( index )->GetData();
1161}
1162
86909f4c
VZ
1163wxSizerItem* wxSizer::GetItemById( int id, bool recursive )
1164{
1165 // This gets a sizer item by the id of the sizer item
1166 // and NOT the id of a window if the item is a window.
1167
1168 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1169 while (node)
1170 {
1171 wxSizerItem *item = node->GetData();
1172
1173 if (item->GetId() == id)
1174 {
1175 return item;
1176 }
1177 else if (recursive && item->IsSizer())
1178 {
1179 wxSizerItem *subitem = item->GetSizer()->GetItemById( id, true );
1180 if (subitem)
1181 return subitem;
1182 }
1183
1184 node = node->GetNext();
1185 }
1186
1187 return NULL;
1188}
1189
9f13661f
WS
1190bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
1191{
1192 wxSizerItem *item = GetItem( window, recursive );
1193
1194 if ( item )
1195 {
1196 item->Show( show );
1197 return true;
1198 }
1199
1200 return false;
1201}
1202
1203bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
1204{
1205 wxSizerItem *item = GetItem( sizer, recursive );
1206
1207 if ( item )
1208 {
1209 item->Show( show );
1210 return true;
1211 }
1212
8b2bac62 1213 return false;
2b5f62a0
VZ
1214}
1215
8b2bac62 1216bool wxSizer::Show( size_t index, bool show)
2b5f62a0 1217{
9f13661f 1218 wxSizerItem *item = GetItem( index );
2b5f62a0 1219
9f13661f
WS
1220 if ( item )
1221 {
1222 item->Show( show );
1223 return true;
1224 }
8b2bac62 1225
9f13661f 1226 return false;
12a3f227 1227}
2b5f62a0 1228
12a3f227
RL
1229void wxSizer::ShowItems( bool show )
1230{
222ed1d6 1231 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
1232 while (node)
1233 {
1234 node->GetData()->Show( show );
1235 node = node->GetNext();
2b5f62a0
VZ
1236 }
1237}
1238
9cbee2ce 1239bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 1240{
222ed1d6 1241 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1242 while (node)
1243 {
12a3f227 1244 wxSizerItem *item = node->GetData();
dc259b79 1245
12a3f227 1246 if (item->GetWindow() == window)
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( wxSizer *sizer ) const
2b5f62a0 1259{
222ed1d6 1260 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1261 while (node)
1262 {
12a3f227 1263 wxSizerItem *item = node->GetData();
2b5f62a0 1264
12a3f227 1265 if (item->GetSizer() == sizer)
2b5f62a0
VZ
1266 {
1267 return item->IsShown();
1268 }
12a3f227 1269 node = node->GetNext();
2b5f62a0
VZ
1270 }
1271
12a3f227
RL
1272 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1273
e0d8fb45 1274 return false;
2b5f62a0
VZ
1275}
1276
9cbee2ce 1277bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
1278{
1279 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 1280 false,
12a3f227
RL
1281 _T("IsShown index is out of range") );
1282
1283 return m_children.Item( index )->GetData()->IsShown();
1284}
1285
1286
f6bcfd97
BP
1287//---------------------------------------------------------------------------
1288// wxGridSizer
1289//---------------------------------------------------------------------------
1290
1291wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
902725ee 1292 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
12a3f227
RL
1293 , m_cols( cols )
1294 , m_vgap( vgap )
1295 , m_hgap( hgap )
f6bcfd97 1296{
f6bcfd97
BP
1297}
1298
1299wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
902725ee 1300 : m_rows( cols == 0 ? 1 : 0 )
12a3f227
RL
1301 , m_cols( cols )
1302 , m_vgap( vgap )
1303 , m_hgap( hgap )
f6bcfd97 1304{
f6bcfd97
BP
1305}
1306
0ca5105b 1307int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 1308{
f6bcfd97 1309 int nitems = m_children.GetCount();
2b5f62a0 1310 if ( nitems)
0ca5105b
VZ
1311 {
1312 if ( m_cols )
1313 {
1314 ncols = m_cols;
1315 nrows = (nitems + m_cols - 1) / m_cols;
1316 }
1317 else if ( m_rows )
1318 {
1319 ncols = (nitems + m_rows - 1) / m_rows;
1320 nrows = m_rows;
1321 }
1322 else // 0 columns, 0 rows?
1323 {
1324 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 1325
0ca5105b
VZ
1326 nrows = ncols = 0;
1327 }
1328 }
1329
1330 return nitems;
1331}
1332
1333void wxGridSizer::RecalcSizes()
1334{
1335 int nitems, nrows, ncols;
1336 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1337 return;
f6bcfd97
BP
1338
1339 wxSize sz( GetSize() );
1340 wxPoint pt( GetPosition() );
3ca6a5f0
BP
1341
1342 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1343 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
1344
1345 int x = pt.x;
1346 for (int c = 0; c < ncols; c++)
1347 {
1348 int y = pt.y;
1349 for (int r = 0; r < nrows; r++)
1350 {
1351 int i = r * ncols + c;
1352 if (i < nitems)
1353 {
222ed1d6 1354 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1355
1356 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 1357
12a3f227 1358 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1359 }
1360 y = y + h + m_vgap;
1361 }
1362 x = x + w + m_hgap;
1363 }
1364}
1365
1366wxSize wxGridSizer::CalcMin()
1367{
196be0f1
JS
1368 int nrows, ncols;
1369 if ( CalcRowsCols(nrows, ncols) == 0 )
b3f1734f 1370 return wxSize();
f6bcfd97 1371
4f469fb5 1372 // Find the max width and height for any component
f6bcfd97
BP
1373 int w = 0;
1374 int h = 0;
3ca6a5f0 1375
222ed1d6 1376 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1377 while (node)
1378 {
12a3f227
RL
1379 wxSizerItem *item = node->GetData();
1380 wxSize sz( item->CalcMin() );
1381
f6bcfd97
BP
1382 w = wxMax( w, sz.x );
1383 h = wxMax( h, sz.y );
3ca6a5f0 1384
12a3f227 1385 node = node->GetNext();
f6bcfd97 1386 }
3ca6a5f0 1387
3d2085a4 1388 // In case we have a nested sizer with a two step algo , give it
15f7c305
RR
1389 // a chance to adjust to that (we give it width component)
1390 node = m_children.GetFirst();
1391 bool didChangeMinSize = false;
1392 while (node)
1393 {
1394 wxSizerItem *item = node->GetData();
1395 didChangeMinSize |= item->InformFirstDirection( wxHORIZONTAL, w, -1 );
3d2085a4 1396
15f7c305
RR
1397 node = node->GetNext();
1398 }
3d2085a4 1399
15f7c305
RR
1400 // And redo iteration in case min size changed
1401 if( didChangeMinSize )
1402 {
1403 node = m_children.GetFirst();
1404 w = h = 0;
1405 while (node)
1406 {
1407 wxSizerItem *item = node->GetData();
1408 wxSize sz( item->GetMinSizeWithBorder() );
1409
1410 w = wxMax( w, sz.x );
1411 h = wxMax( h, sz.y );
1412
1413 node = node->GetNext();
3d2085a4 1414 }
15f7c305 1415 }
3d2085a4 1416
12a3f227
RL
1417 return wxSize( ncols * w + (ncols-1) * m_hgap,
1418 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
1419}
1420
1421void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1422{
1423 wxPoint pt( x,y );
8b2bac62 1424 wxSize sz( item->GetMinSizeWithBorder() );
f6bcfd97
BP
1425 int flag = item->GetFlag();
1426
1427 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1428 {
1429 sz = wxSize(w, h);
1430 }
1431 else
1432 {
1433 if (flag & wxALIGN_CENTER_HORIZONTAL)
1434 {
559b747d 1435 pt.x = x + (w - sz.x) / 2;
f6bcfd97
BP
1436 }
1437 else if (flag & wxALIGN_RIGHT)
1438 {
559b747d 1439 pt.x = x + (w - sz.x);
f6bcfd97 1440 }
3ca6a5f0 1441
f6bcfd97
BP
1442 if (flag & wxALIGN_CENTER_VERTICAL)
1443 {
559b747d 1444 pt.y = y + (h - sz.y) / 2;
f6bcfd97
BP
1445 }
1446 else if (flag & wxALIGN_BOTTOM)
1447 {
559b747d 1448 pt.y = y + (h - sz.y);
f6bcfd97
BP
1449 }
1450 }
3ca6a5f0 1451
f6bcfd97
BP
1452 item->SetDimension(pt, sz);
1453}
1454
1455//---------------------------------------------------------------------------
1456// wxFlexGridSizer
1457//---------------------------------------------------------------------------
1458
1459wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1460 : wxGridSizer( rows, cols, vgap, hgap ),
1461 m_flexDirection(wxBOTH),
1462 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1463{
f6bcfd97
BP
1464}
1465
1466wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1467 : wxGridSizer( cols, vgap, hgap ),
1468 m_flexDirection(wxBOTH),
1469 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1470{
f6bcfd97 1471}
3ca6a5f0 1472
f6bcfd97
BP
1473wxFlexGridSizer::~wxFlexGridSizer()
1474{
f6bcfd97
BP
1475}
1476
1477void wxFlexGridSizer::RecalcSizes()
1478{
74ab5f5b
VZ
1479 int nrows, ncols;
1480 if ( !CalcRowsCols(nrows, ncols) )
f6bcfd97
BP
1481 return;
1482
97800f66
VZ
1483 const wxPoint pt(GetPosition());
1484 const wxSize sz(GetSize());
3ca6a5f0 1485
97800f66 1486 AdjustForGrowables(sz);
f6bcfd97 1487
97800f66 1488 wxSizerItemList::const_iterator i = m_children.begin();
cc67d082
VZ
1489 const wxSizerItemList::const_iterator end = m_children.end();
1490
97800f66
VZ
1491 int y = 0;
1492 for ( int r = 0; r < nrows; r++ )
f6bcfd97 1493 {
97800f66 1494 if ( m_rowHeights[r] == -1 )
f6bcfd97 1495 {
97800f66
VZ
1496 // this row is entirely hidden, skip it
1497 for ( int c = 0; c < ncols; c++ )
cc67d082
VZ
1498 {
1499 if ( i == end )
1500 return;
1501
97800f66 1502 ++i;
cc67d082 1503 }
12a3f227 1504
97800f66
VZ
1505 continue;
1506 }
3ca6a5f0 1507
97800f66
VZ
1508 const int hrow = m_rowHeights[r];
1509 int h = sz.y - y; // max remaining height, don't overflow it
1510 if ( hrow < h )
1511 h = hrow;
3ca6a5f0 1512
97800f66 1513 int x = 0;
cc67d082 1514 for ( int c = 0; c < ncols && i != end; c++, ++i )
97800f66
VZ
1515 {
1516 const int wcol = m_colWidths[c];
1517
1518 if ( wcol == -1 )
1519 continue;
1520
97800f66
VZ
1521 int w = sz.x - x; // max possible value, ensure we don't overflow
1522 if ( wcol < w )
1523 w = wcol;
1524
1525 SetItemBounds(*i, pt.x + x, pt.y + y, w, h);
1526
1527 x += wcol + m_hgap;
f6bcfd97 1528 }
97800f66 1529
cc67d082
VZ
1530 if ( i == end )
1531 return;
1532
97800f66 1533 y += hrow + m_vgap;
f6bcfd97
BP
1534 }
1535}
1536
97800f66
VZ
1537// helper function used in CalcMin() to sum up the sizes of non-hidden items
1538static int SumArraySizes(const wxArrayInt& sizes, int gap)
1539{
1540 // Sum total minimum size, including gaps between rows/columns.
1541 // -1 is used as a magic number meaning empty row/column.
1542 int total = 0;
1543
1544 const size_t count = sizes.size();
1545 for ( size_t n = 0; n < count; n++ )
1546 {
1547 if ( sizes[n] != -1 )
1548 {
1549 if ( total )
1550 total += gap; // separate from the previous column
1551
1552 total += sizes[n];
1553 }
1554 }
1555
1556 return total;
1557}
1558
15f7c305 1559void wxFlexGridSizer::FindWidthsAndHeights(int nrows, int ncols)
f6bcfd97 1560{
97800f66 1561 // We have to recalculate the sizes in case the item minimum size has
395a82b1
VZ
1562 // changed since the previous layout, or the item has been hidden using
1563 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1564 // dimension of the row/column will be -1, indicating that the column
1565 // itself is hidden.
97800f66
VZ
1566 m_rowHeights.assign(nrows, -1);
1567 m_colWidths.assign(ncols, -1);
1568
1569 // n is the index of the item in left-to-right top-to-bottom order
1570 size_t n = 0;
1571 for ( wxSizerItemList::iterator i = m_children.begin();
1572 i != m_children.end();
1573 ++i, ++n )
f6bcfd97 1574 {
97800f66 1575 wxSizerItem * const item = *i;
55f9f0cb
VZ
1576 if ( item->IsShown() )
1577 {
3d2085a4 1578 // NOTE: Not doing the calculation here, this is just
15f7c305
RR
1579 // for finding max values.
1580 const wxSize sz(item->GetMinSizeWithBorder());
12a3f227 1581
97800f66
VZ
1582 const int row = n / ncols;
1583 const int col = n % ncols;
3ca6a5f0 1584
97800f66
VZ
1585 if ( sz.y > m_rowHeights[row] )
1586 m_rowHeights[row] = sz.y;
1587 if ( sz.x > m_colWidths[col] )
1588 m_colWidths[col] = sz.x;
1589 }
f6bcfd97 1590 }
3ca6a5f0 1591
20b35a69 1592 AdjustForFlexDirection();
8b2bac62 1593
97800f66
VZ
1594 m_calculatedMinSize = wxSize(SumArraySizes(m_colWidths, m_hgap),
1595 SumArraySizes(m_rowHeights, m_vgap));
15f7c305
RR
1596}
1597
1598wxSize wxFlexGridSizer::CalcMin()
1599{
1600 int nrows,
1601 ncols;
1602
1603 // Number of rows/columns can change as items are added or removed.
1604 if ( !CalcRowsCols(nrows, ncols) )
1605 return wxSize();
1606
1607
1608 // We have to recalculate the sizes in case the item minimum size has
1609 // changed since the previous layout, or the item has been hidden using
1610 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1611 // dimension of the row/column will be -1, indicating that the column
1612 // itself is hidden.
1613 m_rowHeights.assign(nrows, -1);
1614 m_colWidths.assign(ncols, -1);
1615
1616 // n is the index of the item in left-to-right top-to-bottom order
1617 size_t n = 0;
1618 for ( wxSizerItemList::iterator i = m_children.begin();
1619 i != m_children.end();
1620 ++i, ++n )
1621 {
1622 wxSizerItem * const item = *i;
1623 if ( item->IsShown() )
1624 {
1625 item->CalcMin();
1626 }
1627 }
1628
3d2085a4 1629 // The stage of looking for max values in each row/column has been
15f7c305
RR
1630 // made a separate function, since it's reused in AdjustForGrowables.
1631 FindWidthsAndHeights(nrows,ncols);
97800f66 1632
ba763a45 1633 return m_calculatedMinSize;
20b35a69
RD
1634}
1635
1636void wxFlexGridSizer::AdjustForFlexDirection()
1637{
1638 // the logic in CalcMin works when we resize flexibly in both directions
1639 // but maybe this is not the case
5d76f462
VZ
1640 if ( m_flexDirection != wxBOTH )
1641 {
1642 // select the array corresponding to the direction in which we do *not*
1643 // resize flexibly
1644 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1645 : m_rowHeights;
1646
4a10ea8b 1647 const size_t count = array.GetCount();
5d76f462
VZ
1648
1649 // find the largest value in this array
4a10ea8b
MW
1650 size_t n;
1651 int largest = 0;
1652
5d76f462
VZ
1653 for ( n = 0; n < count; ++n )
1654 {
1655 if ( array[n] > largest )
1656 largest = array[n];
1657 }
1658
1659 // and now fill it with the largest value
1660 for ( n = 0; n < count; ++n )
1661 {
b9a325a1
VZ
1662 // don't touch hidden rows
1663 if ( array[n] != -1 )
1664 array[n] = largest;
5d76f462
VZ
1665 }
1666 }
8b2bac62 1667}
5d76f462 1668
97800f66
VZ
1669// helper of AdjustForGrowables() which is called for rows/columns separately
1670//
1671// parameters:
1672// delta: the extra space, we do nothing unless it's positive
1673// growable: indices or growable rows/cols in sizes array
1674// sizes: the height/widths of rows/cols to adjust
1675// proportions: proportions of the growable rows/cols or NULL if they all
1676// should be assumed to have proportion of 1
1677static void
1678DoAdjustForGrowables(int delta,
1679 const wxArrayInt& growable,
1680 wxArrayInt& sizes,
1681 const wxArrayInt *proportions)
1682{
1683 if ( delta <= 0 )
1684 return;
3ca6a5f0 1685
97800f66
VZ
1686 // total sum of proportions of all non-hidden rows
1687 int sum_proportions = 0;
8b2bac62 1688
97800f66
VZ
1689 // number of currently shown growable rows
1690 int num = 0;
3ca6a5f0 1691
97800f66
VZ
1692 const int max_idx = sizes.size();
1693
1694 const size_t count = growable.size();
1695 size_t idx;
1696 for ( idx = 0; idx < count; idx++ )
20b35a69 1697 {
97800f66
VZ
1698 // Since the number of rows/columns can change as items are
1699 // inserted/deleted, we need to verify at runtime that the
1700 // requested growable rows/columns are still valid.
1701 if ( growable[idx] >= max_idx )
1702 continue;
1703
1704 // If all items in a row/column are hidden, that row/column will
1705 // have a dimension of -1. This causes the row/column to be
1706 // hidden completely.
1707 if ( sizes[growable[idx]] == -1 )
1708 continue;
1709
1710 if ( proportions )
1711 sum_proportions += (*proportions)[idx];
1712
1713 num++;
20b35a69
RD
1714 }
1715
97800f66
VZ
1716 if ( !num )
1717 return;
1718
1719 // the remaining extra free space, adjusted during each iteration
1720 for ( idx = 0; idx < count; idx++ )
20b35a69 1721 {
97800f66
VZ
1722 if ( growable[idx] >= max_idx )
1723 continue;
8b2bac62 1724
97800f66
VZ
1725 if ( sizes[ growable[idx] ] == -1 )
1726 continue;
20b35a69 1727
97800f66
VZ
1728 int cur_delta;
1729 if ( sum_proportions == 0 )
20b35a69 1730 {
97800f66
VZ
1731 // no growable rows -- divide extra space evenly among all
1732 cur_delta = delta/num;
1733 num--;
20b35a69 1734 }
97800f66
VZ
1735 else // allocate extra space proportionally
1736 {
1737 const int cur_prop = (*proportions)[idx];
1738 cur_delta = (delta*cur_prop)/sum_proportions;
1739 sum_proportions -= cur_prop;
1740 }
1741
1742 sizes[growable[idx]] += cur_delta;
1743 delta -= cur_delta;
20b35a69 1744 }
97800f66
VZ
1745}
1746
1747void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
1748{
15f7c305 1749 if ( (m_flexDirection & wxHORIZONTAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
97800f66 1750 {
97800f66
VZ
1751 DoAdjustForGrowables
1752 (
15f7c305
RR
1753 sz.x - m_calculatedMinSize.x,
1754 m_growableCols,
1755 m_colWidths,
1756 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
97800f66
VZ
1757 : NULL
1758 );
3d2085a4
VZ
1759
1760 // This gives nested objects that benefit from knowing one size
1761 // component in advance the chance to use that.
15f7c305
RR
1762 bool didAdjustMinSize = false;
1763 int nrows, ncols;
1764 CalcRowsCols(nrows, ncols);
3d2085a4 1765
15f7c305
RR
1766 // Iterate over all items and inform about column width
1767 size_t n = 0;
1768 for ( wxSizerItemList::iterator i = m_children.begin();
1769 i != m_children.end();
1770 ++i, ++n )
1771 {
1772 const int col = n % ncols;
1773 didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
97800f66
VZ
1774 }
1775
3d2085a4 1776 // Only redo if info was actually used
15f7c305 1777 if( didAdjustMinSize )
20b35a69 1778 {
97800f66
VZ
1779 DoAdjustForGrowables
1780 (
1781 sz.x - m_calculatedMinSize.x,
1782 m_growableCols,
1783 m_colWidths,
1784 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
1785 : NULL
1786 );
20b35a69 1787 }
f6bcfd97
BP
1788}
1789
15f7c305
RR
1790 if ( (m_flexDirection & wxVERTICAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
1791 {
1792 // pass NULL instead of proportions if the grow mode is ALL as we
1793 // should treat all rows as having proportion of 1 then
1794 DoAdjustForGrowables
1795 (
1796 sz.y - m_calculatedMinSize.y,
1797 m_growableRows,
1798 m_rowHeights,
1799 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableRowsProportions
1800 : NULL
1801 );
1802 }
1803}
1804
20b35a69 1805
e8800dcf 1806void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1807{
1808 m_growableRows.Add( idx );
e8800dcf 1809 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1810}
1811
e8800dcf 1812void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1813{
1814 m_growableCols.Add( idx );
e8800dcf 1815 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1816}
1817
ca243008
VZ
1818// helper function for RemoveGrowableCol/Row()
1819static void
1820DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1821{
1822 const size_t count = items.size();
1823 for ( size_t n = 0; n < count; n++ )
1824 {
1825 if ( (size_t)items[n] == idx )
1826 {
1827 items.RemoveAt(n);
1828 proportions.RemoveAt(n);
1829 return;
1830 }
1831 }
1832
1833 wxFAIL_MSG( _T("column/row is already not growable") );
1834}
1835
8d2474f4 1836void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
f6bcfd97 1837{
ca243008
VZ
1838 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1839}
1840
1841void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1842{
1843 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
f6bcfd97
BP
1844}
1845
c62ac5b6 1846//---------------------------------------------------------------------------
92afa2b1 1847// wxBoxSizer
61d514bb
RR
1848//---------------------------------------------------------------------------
1849
92afa2b1 1850void wxBoxSizer::RecalcSizes()
61d514bb 1851{
89064717 1852 if ( m_children.empty() )
61d514bb 1853 return;
0c0d686f 1854
3d2085a4 1855 const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
15f7c305 1856
89064717
VZ
1857 // the amount of free space which we should redistribute among the
1858 // stretchable items (i.e. those with non zero proportion)
3d2085a4
VZ
1859 int delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1860
0c0d686f 1861
15f7c305
RR
1862 // Inform child items about the size in minor direction, that can
1863 // change how much free space we have in major dir and how to distribute it.
1864 int majorMinSum = 0;
82287aae
CE
1865 wxSizerItemList::const_iterator i ;
1866 for ( i = m_children.begin();
15f7c305
RR
1867 i != m_children.end();
1868 ++i )
1869 {
1870 wxSizerItem * const item = *i;
1871
1872 if ( !item->IsShown() )
1873 continue;
1874
1875 wxSize szMinPrev = item->GetMinSizeWithBorder();
1876 item->InformFirstDirection(m_orient^wxBOTH,totalMinorSize,delta);
1877 wxSize szMin = item->GetMinSizeWithBorder();
3d2085a4 1878 int deltaChange = GetSizeInMajorDir(szMin-szMinPrev);
15f7c305
RR
1879 if( deltaChange )
1880 {
3d2085a4
VZ
1881 // Since we passed available space along to the item, it should not
1882 // take too much, so delta should not become negative.
1883 delta -= deltaChange;
15f7c305 1884 }
3d2085a4 1885 majorMinSum += GetSizeInMajorDir(item->GetMinSizeWithBorder());
15f7c305
RR
1886 }
1887 // And update our min size
1888 SizeInMajorDir(m_minSize) = majorMinSum;
1889
1890
1891 // might have a new delta now
3d2085a4
VZ
1892 delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1893
89064717
VZ
1894 // the position at which we put the next child
1895 wxPoint pt(m_position);
12a3f227 1896
7fca7a73 1897 int totalProportion = m_totalProportion;
82287aae 1898 for ( i = m_children.begin();
89064717
VZ
1899 i != m_children.end();
1900 ++i )
1901 {
1902 wxSizerItem * const item = *i;
2b5f62a0 1903
89064717
VZ
1904 if ( !item->IsShown() )
1905 continue;
3d2085a4
VZ
1906
1907 const wxSize sizeThis(item->GetMinSizeWithBorder());
2b5f62a0 1908
89064717 1909 // adjust the size in the major direction using the proportion
3d2085a4 1910 wxCoord majorSize = GetSizeInMajorDir(sizeThis);
7fca7a73
VZ
1911 const int propItem = item->GetProportion();
1912 if ( propItem )
89064717 1913 {
7fca7a73
VZ
1914 const int deltaItem = (delta * propItem) / totalProportion;
1915
1916 majorSize += deltaItem;
1917
1918 delta -= deltaItem;
1919 totalProportion -= propItem;
89064717 1920 }
2b5f62a0 1921
2b5f62a0 1922
89064717
VZ
1923 // apply the alignment in the minor direction
1924 wxPoint posChild(pt);
2b5f62a0 1925
3d2085a4 1926 wxCoord minorSize = GetSizeInMinorDir(sizeThis);
89064717
VZ
1927 const int flag = item->GetFlag();
1928 if ( flag & (wxEXPAND | wxSHAPED) )
1929 {
1930 minorSize = totalMinorSize;
1931 }
1932 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1933 {
1934 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1935 }
1936 // NB: wxCENTRE is used here only for backwards compatibility,
1937 // wxALIGN_CENTRE should be used in new code
1938 else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1939 {
1940 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1941 }
978af864 1942
2b5f62a0 1943
89064717
VZ
1944 // apply RTL adjustment for horizontal sizers:
1945 if ( !IsVertical() && m_containingWindow )
1946 {
1947 posChild.x = m_containingWindow->AdjustForLayoutDirection
1948 (
1949 posChild.x,
1950 majorSize,
1951 m_size.x
1952 );
3ca6a5f0
BP
1953 }
1954
89064717
VZ
1955 // finally set size of this child and advance to the next one
1956 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1957
1958 PosInMajorDir(pt) += majorSize;
61d514bb
RR
1959 }
1960}
1961
92afa2b1 1962wxSize wxBoxSizer::CalcMin()
61d514bb 1963{
89064717
VZ
1964 m_totalProportion = 0;
1965 m_minSize = wxSize(0, 0);
0c0d686f 1966
89064717
VZ
1967 // calculate the minimal sizes for all items and count sum of proportions
1968 for ( wxSizerItemList::const_iterator i = m_children.begin();
1969 i != m_children.end();
1970 ++i )
85e5cfc9 1971 {
89064717 1972 wxSizerItem * const item = *i;
12a3f227 1973
89064717
VZ
1974 if ( !item->IsShown() )
1975 continue;
12a3f227 1976
3d2085a4
VZ
1977 const wxSize sizeMinThis = item->CalcMin();
1978 SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis);
1979 if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) )
1980 SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis);
85e5cfc9 1981
89064717 1982 m_totalProportion += item->GetProportion();
61d514bb 1983 }
0c0d686f 1984
89064717 1985 return m_minSize;
61d514bb 1986}
27ea1d8a 1987
15f7c305
RR
1988//---------------------------------------------------------------------------
1989// wxWrapSizer
1990//---------------------------------------------------------------------------
1991
3d2085a4
VZ
1992#define wxDEFAULT_PROPORTION_LAST 1000000
1993
1994// User data to hold old proportion for last item on line
15f7c305
RR
1995// (which might be extended)
1996struct wxPropHolder : public wxObject
1997{
1998 wxPropHolder( ) : m_item(0), m_propOld(0) { }
1999 void Init( wxSizerItem *item, int propOld ) { m_item=item; m_propOld=propOld; }
3d2085a4 2000
15f7c305
RR
2001 wxSizerItem *m_item;
2002 int m_propOld;
2003};
2004
2005IMPLEMENT_DYNAMIC_CLASS(wxWrapSizer, wxBoxSizer);
2006
2007wxWrapSizer::wxWrapSizer( int orient, int flags )
3d2085a4
VZ
2008 : wxBoxSizer(orient),
2009 m_prim_size_last( -1 ),
15f7c305
RR
2010 m_rows(orient^wxBOTH),
2011 m_flags(flags)
2012{
2013}
2014
2015wxWrapSizer::~wxWrapSizer()
2016{
2017 // Have to clear grand child items so that they're not deleted twice
2018 for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- )
2019 {
2020 wxSizer *psz = m_rows.GetItem((size_t)ix)->GetSizer();
2021 wxSizerItemList &sl = psz->GetChildren();
2022 while( sl.GetLast() )
2023 sl.Erase( sl.GetLast() );
2024 }
2025}
2026
2027
2028bool wxWrapSizer::InformFirstDirection( int direction, int size, int WXUNUSED(availableOtherDir) )
2029{
2030 if( !direction )
2031 {
3d2085a4
VZ
2032 // Better to keep value, then CalcMin will work better
2033 //m_prim_size_last = -1;
15f7c305
RR
2034 return false;
2035 }
2036 if( direction==m_orient )
2037 {
2038 // The direction is same as our primary, so we can make use of it
3d2085a4 2039 m_prim_size_last = size;
15f7c305
RR
2040 return true;
2041 }
3d2085a4 2042 else
15f7c305
RR
2043 return false;
2044}
2045
2046
2047void wxWrapSizer::AdjustPropLastItem(wxSizer *psz, wxSizerItem *itemLast)
2048{
2049 wxSizerItem *psi = m_rows.GetItem(psz);
2050 wxASSERT(psi);
2051 wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
3d2085a4 2052 if ( !pph )
15f7c305 2053 psi->SetUserData( pph=new wxPropHolder );
3d2085a4 2054
15f7c305
RR
2055 pph->Init( itemLast, itemLast->GetProportion() );
2056 itemLast->SetProportion( wxDEFAULT_PROPORTION_LAST );
2057}
2058
2059void wxWrapSizer::RecalcSizes()
2060{
2061 wxASSERT( m_orient&wxBOTH );
2062 if (m_children.GetCount() == 0)
2063 return;
2064
3d2085a4
VZ
2065 // What we do here is to put our items into child box sizers,
2066 // as many of them as we have lines.
15f7c305
RR
2067
2068 // Empty all items in all rows in owned sizer.
3d2085a4 2069 // We have to access the list directly, since we don't want to
15f7c305
RR
2070 // destroy the wxSizerItems.
2071 for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- ){
3d2085a4
VZ
2072 wxSizerItem *psi = m_rows.GetItem( (size_t)ix );
2073
2074 // Restore proportion for last item on line (if item has not been deleted)
2075 wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
2076 if( pph && GetChildren().Find(pph->m_item) )
2077 pph->m_item->SetProportion(pph->m_propOld);
2078
15f7c305
RR
2079 wxSizer *psz = psi->GetSizer();
2080 wxASSERT( psz );
2081 wxSizerItemList &sl = psz->GetChildren();
2082 while( sl.GetLast() )
2083 sl.Erase( sl.GetLast() );
2084 }
3d2085a4 2085
15f7c305 2086 int lineSumMajor = 0;
3d2085a4
VZ
2087 int majorSize = GetSizeInMajorDir(m_size);
2088
15f7c305
RR
2089 // Make sure we have at least one child sizer
2090 m_n_line = 1;
3d2085a4 2091 if( !m_rows.GetChildren().GetCount() )
15f7c305 2092 m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
3d2085a4 2093
15f7c305
RR
2094 // The sizer where to insert items in
2095 wxSizer *psz = m_rows.GetItem((size_t)0)->GetSizer();
2096 wxASSERT( psz );
3d2085a4 2097
15f7c305
RR
2098 // Now put our child items into child sizers instead
2099 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2100 wxSizerItem *item = NULL, *itemLast=NULL;
2101 while (node)
2102 {
2103 item = node->GetData();
2104 if ( item->IsShown() )
2105 {
3d2085a4
VZ
2106 wxSize minSz = item->GetMinSize();
2107 int minSzMajor = GetSizeInMajorDir(minSz);
2108
15f7c305 2109 // More space on this line?
3d2085a4 2110 if( !lineSumMajor || lineSumMajor+minSzMajor<=majorSize )
15f7c305
RR
2111 {
2112 lineSumMajor += minSzMajor;
2113 }
2114 else
2115 {
2116 lineSumMajor = minSzMajor;
2117 // Get a new empty sizer to insert into
2118 if( (int)m_rows.GetChildren().GetCount()<=m_n_line )
2119 m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
3d2085a4
VZ
2120
2121 // If we have extend-last-on-each-line mode, then do so now
15f7c305
RR
2122 // Note: We must store old proportion value then.
2123 if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
3d2085a4
VZ
2124 AdjustPropLastItem(psz,itemLast);
2125
15f7c305
RR
2126 // The sizer where to insert items in
2127 psz = m_rows.GetItem(m_n_line++)->GetSizer();
2128 }
3d2085a4 2129 itemLast = item;
15f7c305 2130 psz->Add( item );
3d2085a4
VZ
2131 // If item is a window, it now has a pointer to the child sizer,
2132 // which is wrong. Set it to point to us.
15f7c305 2133 if( item->GetWindow() )
3d2085a4 2134 item->GetWindow()->SetContainingSizer( this );
15f7c305
RR
2135 }
2136 node = node->GetNext();
2137 }
2138
3d2085a4 2139 // If we have extend-last-on-each-line mode, then do so now
15f7c305
RR
2140 if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
2141 AdjustPropLastItem(psz,itemLast);
3d2085a4
VZ
2142
2143 // If we have more sizers than lines, remove them
15f7c305
RR
2144 while( (int)m_rows.GetChildren().GetCount()>m_n_line )
2145 m_rows.Remove( m_n_line );
2146
2147 // Now do layout on row sizer
2148 m_rows.SetDimension( m_position.x, m_position.y, m_size.x, m_size.y );
3d2085a4 2149
15f7c305 2150 // Remember this to next time (will be overridden by InformFirstDirection if used)
3d2085a4 2151 m_prim_size_last = GetSizeInMajorDir(m_size);
15f7c305
RR
2152}
2153
2154
2155wxSize wxWrapSizer::CalcMin()
2156{
2157 if (m_children.GetCount() == 0)
2158 return wxSize();
2159
2160 // Algorithm for calculating min size: (assuming horizontal orientation)
2161 // X: Max width of all members
3d2085a4 2162 // Y: Based on last X, calculate how many lines needed
15f7c305 2163 // First time around, assume all items fits on one line
3d2085a4 2164
15f7c305
RR
2165 int maxMajor = 0;
2166 int minorSum = 0;
2167 int lineMaxMinor = 0;
2168 int lineSumMajor = 0;
2169 m_n_line = 0;
3d2085a4 2170
15f7c305
RR
2171 // precalc item minsizes and fit on lines (preliminary)
2172 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2173 while (node)
2174 {
2175 wxSizerItem *item = node->GetData();
2176 if ( item->IsShown() )
2177 {
2178 wxSize minSz = item->CalcMin();
3d2085a4
VZ
2179 int szMajor = GetSizeInMajorDir(minSz);
2180 int szMinor = GetSizeInMinorDir(minSz);
15f7c305
RR
2181 if( szMajor>maxMajor ) maxMajor = szMajor;
2182 // More space on this line?
3d2085a4
VZ
2183 if( m_prim_size_last<0 || !lineSumMajor ||
2184 lineSumMajor+szMajor<=m_prim_size_last )
15f7c305
RR
2185 {
2186 lineSumMajor += szMajor;
3d2085a4 2187 if( szMinor>lineMaxMinor )
15f7c305
RR
2188 lineMaxMinor = szMinor;
2189 }
2190 else
2191 {
2192 minorSum += lineMaxMinor; // Add height of highest item on last line
2193 m_n_line++;
2194 lineMaxMinor = szMinor;
2195 lineSumMajor = szMajor;
2196 }
2197 }
2198 node = node->GetNext();
2199 }
2200 minorSum += lineMaxMinor; // Add height of highest item on last line
2201
3d2085a4
VZ
2202 m_minSize = SizeFromMajorMinor(maxMajor, minorSum);
2203 return m_minSize;
15f7c305
RR
2204}
2205
27ea1d8a
RR
2206//---------------------------------------------------------------------------
2207// wxStaticBoxSizer
2208//---------------------------------------------------------------------------
2209
1e6feb95
VZ
2210#if wxUSE_STATBOX
2211
27ea1d8a 2212wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
e978011a
VZ
2213 : wxBoxSizer( orient ),
2214 m_staticBox( box )
27ea1d8a 2215{
223d09f6 2216 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
e978011a
VZ
2217
2218 // do this so that our Detach() is called if the static box is destroyed
2219 // before we are
2220 m_staticBox->SetContainingSizer(this);
27ea1d8a 2221}
0c0d686f 2222
6c1635b5
VZ
2223wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
2224 : wxBoxSizer(orient),
2225 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
2226{
e978011a
VZ
2227 // same as above
2228 m_staticBox->SetContainingSizer(this);
6c1635b5
VZ
2229}
2230
649cfca1
VZ
2231wxStaticBoxSizer::~wxStaticBoxSizer()
2232{
2233 delete m_staticBox;
2234}
2235
12a3f227
RL
2236static void GetStaticBoxBorders( wxStaticBox *box,
2237 int *borderTop,
2238 int *borderOther)
84028727
VZ
2239{
2240 // this has to be done platform by platform as there is no way to
2241 // guess the thickness of a wxStaticBox border
5dd070c2 2242 box->GetBordersForSizer(borderTop, borderOther);
84028727
VZ
2243}
2244
27ea1d8a
RR
2245void wxStaticBoxSizer::RecalcSizes()
2246{
84028727
VZ
2247 int top_border, other_border;
2248 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
2249
2250 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 2251
27ea1d8a
RR
2252 wxPoint old_pos( m_position );
2253 m_position.x += other_border;
2254 m_position.y += top_border;
2255 wxSize old_size( m_size );
2256 m_size.x -= 2*other_border;
2257 m_size.y -= top_border + other_border;
0c0d686f 2258
27ea1d8a 2259 wxBoxSizer::RecalcSizes();
0c0d686f 2260
27ea1d8a
RR
2261 m_position = old_pos;
2262 m_size = old_size;
2263}
2264
2265wxSize wxStaticBoxSizer::CalcMin()
2266{
84028727
VZ
2267 int top_border, other_border;
2268 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 2269
27ea1d8a 2270 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 2271 ret.x += 2*other_border;
27ea1d8a 2272 ret.y += other_border + top_border;
0c0d686f 2273
27ea1d8a
RR
2274 return ret;
2275}
83edc0a5 2276
eb2a7883
VZ
2277void wxStaticBoxSizer::ShowItems( bool show )
2278{
2279 m_staticBox->Show( show );
2280 wxBoxSizer::ShowItems( show );
2281}
2282
e978011a
VZ
2283bool wxStaticBoxSizer::Detach( wxWindow *window )
2284{
2285 // avoid deleting m_staticBox in our dtor if it's being detached from the
2286 // sizer (which can happen because it's being already destroyed for
2287 // example)
2288 if ( window == m_staticBox )
2289 {
2290 m_staticBox = NULL;
2291 return true;
2292 }
2293
2294 return wxSizer::Detach( window );
2295}
2296
1e6feb95
VZ
2297#endif // wxUSE_STATBOX
2298
974c2a59
WS
2299#if wxUSE_BUTTON
2300
acf2ac37
RR
2301wxStdDialogButtonSizer::wxStdDialogButtonSizer()
2302 : wxBoxSizer(wxHORIZONTAL)
2303{
94f53923
JS
2304 // Vertical buttons with lots of space on either side
2305 // looks rubbish on WinCE, so let's not do this for now.
2306 // If we are going to use vertical buttons, we should
2307 // put the sizer to the right of other controls in the dialog,
2308 // and that's beyond the scope of this sizer.
2309#ifndef __WXWINCE__
acf2ac37 2310 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
974c2a59 2311 // If we have a PDA screen, put yes/no button over
acf2ac37
RR
2312 // all other buttons, otherwise on the left side.
2313 if (is_pda)
2314 m_orient = wxVERTICAL;
94f53923 2315#endif
974c2a59 2316
acf2ac37
RR
2317 m_buttonAffirmative = NULL;
2318 m_buttonApply = NULL;
2319 m_buttonNegative = NULL;
2320 m_buttonCancel = NULL;
2321 m_buttonHelp = NULL;
2322}
2323
2324void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
2325{
2326 switch (mybutton->GetId())
2327 {
2328 case wxID_OK:
2329 case wxID_YES:
2330 case wxID_SAVE:
2331 m_buttonAffirmative = mybutton;
2332 break;
2333 case wxID_APPLY:
2334 m_buttonApply = mybutton;
2335 break;
2336 case wxID_NO:
2337 m_buttonNegative = mybutton;
2338 break;
2339 case wxID_CANCEL:
57d7f988 2340 case wxID_CLOSE:
acf2ac37
RR
2341 m_buttonCancel = mybutton;
2342 break;
2343 case wxID_HELP:
2997ca30 2344 case wxID_CONTEXT_HELP:
acf2ac37
RR
2345 m_buttonHelp = mybutton;
2346 break;
2347 default:
2348 break;
2349 }
2350}
2351
b181a505
RR
2352void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
2353{
2354 m_buttonAffirmative = button;
2355}
2356
2357void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
2358{
2359 m_buttonNegative = button;
2360}
2361
2362void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
2363{
2364 m_buttonCancel = button;
2365}
2366
718903fe 2367void wxStdDialogButtonSizer::Realize()
acf2ac37
RR
2368{
2369#ifdef __WXMAC__
2370 Add(0, 0, 0, wxLEFT, 6);
2371 if (m_buttonHelp)
974c2a59
WS
2372 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2373
acf2ac37
RR
2374 if (m_buttonNegative){
2375 // HIG POLICE BULLETIN - destructive buttons need extra padding
2376 // 24 pixels on either side
2377 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
2378 }
974c2a59 2379
acf2ac37 2380 // extra whitespace between help/negative and cancel/ok buttons
974c2a59
WS
2381 Add(0, 0, 1, wxEXPAND, 0);
2382
acf2ac37
RR
2383 if (m_buttonCancel){
2384 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2385 // Cancel or help should be default
2386 // m_buttonCancel->SetDefaultButton();
2387 }
974c2a59
WS
2388
2389 // Ugh, Mac doesn't really have apply dialogs, so I'll just
acf2ac37
RR
2390 // figure the best place is between Cancel and OK
2391 if (m_buttonApply)
2392 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
974c2a59 2393
acf2ac37
RR
2394 if (m_buttonAffirmative){
2395 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
974c2a59 2396
acf2ac37
RR
2397 if (m_buttonAffirmative->GetId() == wxID_SAVE){
2398 // these buttons have set labels under Mac so we should use them
2399 m_buttonAffirmative->SetLabel(_("Save"));
d9485f89
RD
2400 if (m_buttonNegative)
2401 m_buttonNegative->SetLabel(_("Don't Save"));
acf2ac37
RR
2402 }
2403 }
974c2a59 2404
acf2ac37
RR
2405 // Extra space around and at the right
2406 Add(12, 24);
2407#elif defined(__WXGTK20__)
2408 Add(0, 0, 0, wxLEFT, 9);
2409 if (m_buttonHelp)
974c2a59
WS
2410 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2411
acf2ac37 2412 // extra whitespace between help and cancel/ok buttons
974c2a59
WS
2413 Add(0, 0, 1, wxEXPAND, 0);
2414
acf2ac37
RR
2415 if (m_buttonNegative){
2416 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2417 }
974c2a59 2418
e6cfcc0d 2419 // according to HIG, in explicit apply windows the order is:
57d7f988
VZ
2420 // [ Help Apply Cancel OK ]
2421 if (m_buttonApply)
2422 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2423
acf2ac37
RR
2424 if (m_buttonCancel){
2425 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2426 // Cancel or help should be default
2427 // m_buttonCancel->SetDefaultButton();
2428 }
974c2a59 2429
acf2ac37
RR
2430 if (m_buttonAffirmative)
2431 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
0f884515
JS
2432#elif defined(__WXMSW__)
2433 // Windows
2434
2435 // right-justify buttons
2436 Add(0, 0, 1, wxEXPAND, 0);
2437
2438 if (m_buttonAffirmative){
2439 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2440 }
2441
2442 if (m_buttonNegative){
2443 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2444 }
2445
2446 if (m_buttonCancel){
2447 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2448 }
2449 if (m_buttonApply)
2450 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2451
2452 if (m_buttonHelp)
2453 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
acf2ac37 2454#else
0f884515 2455 // GTK+1 and any other platform
902725ee 2456
23b1018f 2457 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
acf2ac37 2458 if (m_buttonHelp)
974c2a59
WS
2459 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2460
acf2ac37 2461 // extra whitespace between help and cancel/ok buttons
974c2a59 2462 Add(0, 0, 1, wxEXPAND, 0);
acf2ac37
RR
2463
2464 if (m_buttonApply)
2465 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
974c2a59 2466
acf2ac37
RR
2467 if (m_buttonAffirmative){
2468 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2469 }
974c2a59 2470
acf2ac37
RR
2471 if (m_buttonNegative){
2472 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2473 }
974c2a59 2474
acf2ac37 2475 if (m_buttonCancel){
23b1018f 2476 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
acf2ac37
RR
2477 // Cancel or help should be default
2478 // m_buttonCancel->SetDefaultButton();
2479 }
974c2a59 2480
acf2ac37
RR
2481#endif
2482}
adbf2d73 2483
974c2a59 2484#endif // wxUSE_BUTTON