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