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