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