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