]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
mac cleanup, pure cgcolor
[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;
653d72b3
CE
1714#ifndef __DMC__
1715 // DMC doesn't distinguish between
1716 // int SizeInMajorDir(const wxSize& sz) const
1717 // and int& SizeInMajorDir(wxSize& sz)
1718 const
1719#endif
1720 wxSize sizeThis(item->GetMinSizeWithBorder());
2b5f62a0 1721
2b5f62a0 1722
89064717
VZ
1723 // adjust the size in the major direction using the proportion
1724 wxCoord majorSize = SizeInMajorDir(sizeThis);
7fca7a73
VZ
1725 const int propItem = item->GetProportion();
1726 if ( propItem )
89064717 1727 {
7fca7a73
VZ
1728 const int deltaItem = (delta * propItem) / totalProportion;
1729
1730 majorSize += deltaItem;
1731
1732 delta -= deltaItem;
1733 totalProportion -= propItem;
89064717 1734 }
2b5f62a0 1735
2b5f62a0 1736
89064717
VZ
1737 // apply the alignment in the minor direction
1738 wxPoint posChild(pt);
2b5f62a0 1739
89064717
VZ
1740 wxCoord minorSize = SizeInMinorDir(sizeThis);
1741 const int flag = item->GetFlag();
1742 if ( flag & (wxEXPAND | wxSHAPED) )
1743 {
1744 minorSize = totalMinorSize;
1745 }
1746 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1747 {
1748 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1749 }
1750 // NB: wxCENTRE is used here only for backwards compatibility,
1751 // wxALIGN_CENTRE should be used in new code
1752 else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1753 {
1754 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1755 }
978af864 1756
2b5f62a0 1757
89064717
VZ
1758 // apply RTL adjustment for horizontal sizers:
1759 if ( !IsVertical() && m_containingWindow )
1760 {
1761 posChild.x = m_containingWindow->AdjustForLayoutDirection
1762 (
1763 posChild.x,
1764 majorSize,
1765 m_size.x
1766 );
3ca6a5f0
BP
1767 }
1768
89064717
VZ
1769 // finally set size of this child and advance to the next one
1770 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1771
1772 PosInMajorDir(pt) += majorSize;
61d514bb
RR
1773 }
1774}
1775
92afa2b1 1776wxSize wxBoxSizer::CalcMin()
61d514bb 1777{
89064717
VZ
1778 m_totalProportion = 0;
1779 m_minSize = wxSize(0, 0);
0c0d686f 1780
89064717
VZ
1781 // calculate the minimal sizes for all items and count sum of proportions
1782 for ( wxSizerItemList::const_iterator i = m_children.begin();
1783 i != m_children.end();
1784 ++i )
85e5cfc9 1785 {
89064717 1786 wxSizerItem * const item = *i;
12a3f227 1787
89064717
VZ
1788 if ( !item->IsShown() )
1789 continue;
653d72b3
CE
1790#ifndef __DMC__
1791 const // see __DMC__ above
1792#endif
1793 wxSize sizeMinThis = item->CalcMin();
12a3f227 1794
89064717
VZ
1795 SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
1796 if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
1797 SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
85e5cfc9 1798
89064717 1799 m_totalProportion += item->GetProportion();
61d514bb 1800 }
0c0d686f 1801
89064717 1802 return m_minSize;
61d514bb 1803}
27ea1d8a
RR
1804
1805//---------------------------------------------------------------------------
1806// wxStaticBoxSizer
1807//---------------------------------------------------------------------------
1808
1e6feb95
VZ
1809#if wxUSE_STATBOX
1810
27ea1d8a 1811wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
e978011a
VZ
1812 : wxBoxSizer( orient ),
1813 m_staticBox( box )
27ea1d8a 1814{
223d09f6 1815 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
e978011a
VZ
1816
1817 // do this so that our Detach() is called if the static box is destroyed
1818 // before we are
1819 m_staticBox->SetContainingSizer(this);
27ea1d8a 1820}
0c0d686f 1821
6c1635b5
VZ
1822wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1823 : wxBoxSizer(orient),
1824 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1825{
e978011a
VZ
1826 // same as above
1827 m_staticBox->SetContainingSizer(this);
6c1635b5
VZ
1828}
1829
649cfca1
VZ
1830wxStaticBoxSizer::~wxStaticBoxSizer()
1831{
1832 delete m_staticBox;
1833}
1834
12a3f227
RL
1835static void GetStaticBoxBorders( wxStaticBox *box,
1836 int *borderTop,
1837 int *borderOther)
84028727
VZ
1838{
1839 // this has to be done platform by platform as there is no way to
1840 // guess the thickness of a wxStaticBox border
5dd070c2 1841 box->GetBordersForSizer(borderTop, borderOther);
84028727
VZ
1842}
1843
27ea1d8a
RR
1844void wxStaticBoxSizer::RecalcSizes()
1845{
84028727
VZ
1846 int top_border, other_border;
1847 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
1848
1849 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 1850
27ea1d8a
RR
1851 wxPoint old_pos( m_position );
1852 m_position.x += other_border;
1853 m_position.y += top_border;
1854 wxSize old_size( m_size );
1855 m_size.x -= 2*other_border;
1856 m_size.y -= top_border + other_border;
0c0d686f 1857
27ea1d8a 1858 wxBoxSizer::RecalcSizes();
0c0d686f 1859
27ea1d8a
RR
1860 m_position = old_pos;
1861 m_size = old_size;
1862}
1863
1864wxSize wxStaticBoxSizer::CalcMin()
1865{
84028727
VZ
1866 int top_border, other_border;
1867 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 1868
27ea1d8a 1869 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 1870 ret.x += 2*other_border;
27ea1d8a 1871 ret.y += other_border + top_border;
0c0d686f 1872
27ea1d8a
RR
1873 return ret;
1874}
83edc0a5 1875
eb2a7883
VZ
1876void wxStaticBoxSizer::ShowItems( bool show )
1877{
1878 m_staticBox->Show( show );
1879 wxBoxSizer::ShowItems( show );
1880}
1881
e978011a
VZ
1882bool wxStaticBoxSizer::Detach( wxWindow *window )
1883{
1884 // avoid deleting m_staticBox in our dtor if it's being detached from the
1885 // sizer (which can happen because it's being already destroyed for
1886 // example)
1887 if ( window == m_staticBox )
1888 {
1889 m_staticBox = NULL;
1890 return true;
1891 }
1892
1893 return wxSizer::Detach( window );
1894}
1895
1e6feb95
VZ
1896#endif // wxUSE_STATBOX
1897
974c2a59
WS
1898#if wxUSE_BUTTON
1899
acf2ac37
RR
1900wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1901 : wxBoxSizer(wxHORIZONTAL)
1902{
94f53923
JS
1903 // Vertical buttons with lots of space on either side
1904 // looks rubbish on WinCE, so let's not do this for now.
1905 // If we are going to use vertical buttons, we should
1906 // put the sizer to the right of other controls in the dialog,
1907 // and that's beyond the scope of this sizer.
1908#ifndef __WXWINCE__
acf2ac37 1909 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
974c2a59 1910 // If we have a PDA screen, put yes/no button over
acf2ac37
RR
1911 // all other buttons, otherwise on the left side.
1912 if (is_pda)
1913 m_orient = wxVERTICAL;
94f53923 1914#endif
974c2a59 1915
acf2ac37
RR
1916 m_buttonAffirmative = NULL;
1917 m_buttonApply = NULL;
1918 m_buttonNegative = NULL;
1919 m_buttonCancel = NULL;
1920 m_buttonHelp = NULL;
1921}
1922
1923void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1924{
1925 switch (mybutton->GetId())
1926 {
1927 case wxID_OK:
1928 case wxID_YES:
1929 case wxID_SAVE:
1930 m_buttonAffirmative = mybutton;
1931 break;
1932 case wxID_APPLY:
1933 m_buttonApply = mybutton;
1934 break;
1935 case wxID_NO:
1936 m_buttonNegative = mybutton;
1937 break;
1938 case wxID_CANCEL:
57d7f988 1939 case wxID_CLOSE:
acf2ac37
RR
1940 m_buttonCancel = mybutton;
1941 break;
1942 case wxID_HELP:
2997ca30 1943 case wxID_CONTEXT_HELP:
acf2ac37
RR
1944 m_buttonHelp = mybutton;
1945 break;
1946 default:
1947 break;
1948 }
1949}
1950
b181a505
RR
1951void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1952{
1953 m_buttonAffirmative = button;
1954}
1955
1956void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1957{
1958 m_buttonNegative = button;
1959}
1960
1961void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1962{
1963 m_buttonCancel = button;
1964}
1965
718903fe 1966void wxStdDialogButtonSizer::Realize()
acf2ac37
RR
1967{
1968#ifdef __WXMAC__
1969 Add(0, 0, 0, wxLEFT, 6);
1970 if (m_buttonHelp)
974c2a59
WS
1971 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1972
acf2ac37
RR
1973 if (m_buttonNegative){
1974 // HIG POLICE BULLETIN - destructive buttons need extra padding
1975 // 24 pixels on either side
1976 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1977 }
974c2a59 1978
acf2ac37 1979 // extra whitespace between help/negative and cancel/ok buttons
974c2a59
WS
1980 Add(0, 0, 1, wxEXPAND, 0);
1981
acf2ac37
RR
1982 if (m_buttonCancel){
1983 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1984 // Cancel or help should be default
1985 // m_buttonCancel->SetDefaultButton();
1986 }
974c2a59
WS
1987
1988 // Ugh, Mac doesn't really have apply dialogs, so I'll just
acf2ac37
RR
1989 // figure the best place is between Cancel and OK
1990 if (m_buttonApply)
1991 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
974c2a59 1992
acf2ac37
RR
1993 if (m_buttonAffirmative){
1994 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
974c2a59 1995
acf2ac37
RR
1996 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1997 // these buttons have set labels under Mac so we should use them
1998 m_buttonAffirmative->SetLabel(_("Save"));
d9485f89
RD
1999 if (m_buttonNegative)
2000 m_buttonNegative->SetLabel(_("Don't Save"));
acf2ac37
RR
2001 }
2002 }
974c2a59 2003
acf2ac37
RR
2004 // Extra space around and at the right
2005 Add(12, 24);
2006#elif defined(__WXGTK20__)
2007 Add(0, 0, 0, wxLEFT, 9);
2008 if (m_buttonHelp)
974c2a59
WS
2009 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2010
acf2ac37 2011 // extra whitespace between help and cancel/ok buttons
974c2a59
WS
2012 Add(0, 0, 1, wxEXPAND, 0);
2013
acf2ac37
RR
2014 if (m_buttonNegative){
2015 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2016 }
974c2a59 2017
e6cfcc0d 2018 // according to HIG, in explicit apply windows the order is:
57d7f988
VZ
2019 // [ Help Apply Cancel OK ]
2020 if (m_buttonApply)
2021 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2022
acf2ac37
RR
2023 if (m_buttonCancel){
2024 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2025 // Cancel or help should be default
2026 // m_buttonCancel->SetDefaultButton();
2027 }
974c2a59 2028
acf2ac37
RR
2029 if (m_buttonAffirmative)
2030 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
0f884515
JS
2031#elif defined(__WXMSW__)
2032 // Windows
2033
2034 // right-justify buttons
2035 Add(0, 0, 1, wxEXPAND, 0);
2036
2037 if (m_buttonAffirmative){
2038 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2039 }
2040
2041 if (m_buttonNegative){
2042 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2043 }
2044
2045 if (m_buttonCancel){
2046 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2047 }
2048 if (m_buttonApply)
2049 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2050
2051 if (m_buttonHelp)
2052 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
acf2ac37 2053#else
0f884515 2054 // GTK+1 and any other platform
902725ee 2055
23b1018f 2056 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
acf2ac37 2057 if (m_buttonHelp)
974c2a59
WS
2058 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2059
acf2ac37 2060 // extra whitespace between help and cancel/ok buttons
974c2a59 2061 Add(0, 0, 1, wxEXPAND, 0);
acf2ac37
RR
2062
2063 if (m_buttonApply)
2064 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
974c2a59 2065
acf2ac37
RR
2066 if (m_buttonAffirmative){
2067 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2068 }
974c2a59 2069
acf2ac37
RR
2070 if (m_buttonNegative){
2071 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2072 }
974c2a59 2073
acf2ac37 2074 if (m_buttonCancel){
23b1018f 2075 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
acf2ac37
RR
2076 // Cancel or help should be default
2077 // m_buttonCancel->SetDefaultButton();
2078 }
974c2a59 2079
acf2ac37
RR
2080#endif
2081}
adbf2d73 2082
974c2a59 2083#endif // wxUSE_BUTTON