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