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