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