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