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