]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
don't list SetSelection() as being deprecated, it isn't
[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"
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:
e47e063a 483 {
7499628f
RR
484 // Use wxSIZE_FORCE_EVENT here since a sizer item might
485 // have changed alignment or some other property which would
486 // not change the size of the window. In such a case, no
487 // wxSizeEvent would normally be generated and thus the
488 // control wouldn't get layed out correctly here.
50c06297 489 m_window->SetSize(pos.x, pos.y, size.x, size.y,
e47e063a 490 wxSIZE_ALLOW_MINUS_ONE|wxSIZE_FORCE_EVENT );
50c06297 491 break;
e47e063a 492 }
50c06297 493 case Item_Sizer:
49dcc246 494 m_sizer->SetDimension(pos, size);
50c06297
VZ
495 break;
496
497 case Item_Spacer:
498 m_spacer->SetSize(size);
499 break;
500
501 case Item_Max:
502 default:
503 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
504 }
c62ac5b6
RR
505}
506
84f7908b
RR
507void wxSizerItem::DeleteWindows()
508{
50c06297 509 switch ( m_kind )
77aa9abd 510 {
50c06297
VZ
511 case Item_None:
512 case Item_Spacer:
513 break;
514
515 case Item_Window:
caa2490c
RN
516 //We are deleting the window from this sizer - normally
517 //the window destroys the sizer associated with it,
518 //which might destroy this, which we don't want
519 m_window->SetContainingSizer(NULL);
50c06297 520 m_window->Destroy();
caa2490c
RN
521 //Putting this after the switch will result in a spacer
522 //not being deleted properly on destruction
902725ee 523 m_kind = Item_None;
50c06297
VZ
524 break;
525
526 case Item_Sizer:
527 m_sizer->DeleteWindows();
528 break;
529
530 case Item_Max:
531 default:
532 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
77aa9abd 533 }
be90c029 534
84f7908b
RR
535}
536
50c06297 537void wxSizerItem::Show( bool show )
5279a24d 538{
50c06297
VZ
539 switch ( m_kind )
540 {
541 case Item_None:
542 wxFAIL_MSG( _T("can't show uninitialized sizer item") );
543 break;
5279a24d 544
50c06297
VZ
545 case Item_Window:
546 m_window->Show(show);
547 break;
5279a24d 548
50c06297 549 case Item_Sizer:
3a5910cb 550 m_sizer->Show(show);
50c06297
VZ
551 break;
552
553 case Item_Spacer:
554 m_spacer->Show(show);
555 break;
556
557 case Item_Max:
558 default:
559 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
560 }
5279a24d
RR
561}
562
50c06297 563bool wxSizerItem::IsShown() const
12a3f227 564{
0ba6faae
VS
565 if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN )
566 return true;
567
50c06297
VZ
568 switch ( m_kind )
569 {
570 case Item_None:
f1662177
VZ
571 // we may be called from CalcMin(), just return false so that we're
572 // not used
50c06297
VZ
573 break;
574
575 case Item_Window:
576 return m_window->IsShown();
12a3f227 577
50c06297 578 case Item_Sizer:
f303d69f
VZ
579 // arbitrarily decide that if at least one of our elements is
580 // shown, so are we (this arbitrariness is the reason for
581 // deprecating this function)
582 {
29392c81
JS
583 // Some apps (such as dialog editors) depend on an empty sizer still
584 // being laid out correctly and reporting the correct size and position.
585 if (m_sizer->GetChildren().GetCount() == 0)
586 return true;
587
f303d69f
VZ
588 for ( wxSizerItemList::compatibility_iterator
589 node = m_sizer->GetChildren().GetFirst();
590 node;
591 node = node->GetNext() )
592 {
593 if ( node->GetData()->IsShown() )
594 return true;
595 }
596 }
597 return false;
12a3f227 598
50c06297
VZ
599 case Item_Spacer:
600 return m_spacer->IsShown();
601
602 case Item_Max:
603 default:
604 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
605 }
606
607 return false;
12a3f227
RL
608}
609
ca3e85cf 610#if WXWIN_COMPATIBILITY_2_6
12a3f227
RL
611void wxSizerItem::SetOption( int option )
612{
613 SetProportion( option );
614}
615
616int wxSizerItem::GetOption() const
617{
618 return GetProportion();
619}
ca3e85cf 620#endif // WXWIN_COMPATIBILITY_2_6
12a3f227
RL
621
622
5279a24d 623//---------------------------------------------------------------------------
3417c2cd 624// wxSizer
5279a24d
RR
625//---------------------------------------------------------------------------
626
3417c2cd 627wxSizer::~wxSizer()
5279a24d 628{
222ed1d6 629 WX_CLEAR_LIST(wxSizerItemList, m_children);
5279a24d 630}
0c0d686f 631
56eee37f 632wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
12a3f227
RL
633{
634 m_children.Insert( index, item );
0c0d686f 635
50c06297 636 if ( item->GetWindow() )
12a3f227 637 item->GetWindow()->SetContainingSizer( this );
56eee37f 638
e6cfcc0d
JS
639 if ( item->GetSizer() )
640 item->GetSizer()->SetContainingWindow( m_containingWindow );
641
56eee37f 642 return item;
12a3f227
RL
643}
644
e8cfff87
VZ
645void wxSizer::SetContainingWindow(wxWindow *win)
646{
647 if ( win == m_containingWindow )
648 return;
649
650 m_containingWindow = win;
651
652 // set the same window for all nested sizers as well, they also are in the
653 // same window
654 for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
655 node;
656 node = node->GetNext() )
657 {
658 wxSizerItem *const item = node->GetData();
659 wxSizer *const sizer = item->GetSizer();
660
661 if ( sizer )
662 {
663 sizer->SetContainingWindow(win);
664 }
665 }
666}
667
ca3e85cf 668#if WXWIN_COMPATIBILITY_2_6
12a3f227
RL
669bool wxSizer::Remove( wxWindow *window )
670{
671 return Detach( window );
42b4e99e 672}
ca3e85cf 673#endif // WXWIN_COMPATIBILITY_2_6
42b4e99e
RR
674
675bool wxSizer::Remove( wxSizer *sizer )
676{
12a3f227 677 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
0c0d686f 678
222ed1d6 679 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
42b4e99e
RR
680 while (node)
681 {
12a3f227
RL
682 wxSizerItem *item = node->GetData();
683
3ca6a5f0 684 if (item->GetSizer() == sizer)
222ed1d6
MB
685 {
686 delete item;
687 m_children.Erase( node );
688 return true;
689 }
12a3f227
RL
690
691 node = node->GetNext();
42b4e99e 692 }
0c0d686f 693
e0d8fb45 694 return false;
42b4e99e
RR
695}
696
e0d8fb45 697bool wxSizer::Remove( int index )
42b4e99e 698{
e0d8fb45
VZ
699 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
700 false,
12a3f227 701 _T("Remove index is out of range") );
0c0d686f 702
222ed1d6 703 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
0c0d686f 704
e0d8fb45 705 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227 706
a50cf60e 707 delete node->GetData();
222ed1d6 708 m_children.Erase( node );
a50cf60e 709
222ed1d6 710 return true;
42b4e99e 711}
0c0d686f 712
00976fe5
RL
713bool wxSizer::Detach( wxSizer *sizer )
714{
12a3f227 715 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
00976fe5 716
222ed1d6 717 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
00976fe5
RL
718 while (node)
719 {
12a3f227
RL
720 wxSizerItem *item = node->GetData();
721
00976fe5
RL
722 if (item->GetSizer() == sizer)
723 {
96fdbb60 724 item->DetachSizer();
89c20ac1 725 delete item;
222ed1d6
MB
726 m_children.Erase( node );
727 return true;
12a3f227
RL
728 }
729 node = node->GetNext();
730 }
731
e0d8fb45 732 return false;
12a3f227
RL
733}
734
735bool wxSizer::Detach( wxWindow *window )
736{
737 wxASSERT_MSG( window, _T("Detaching NULL window") );
738
222ed1d6 739 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
740 while (node)
741 {
742 wxSizerItem *item = node->GetData();
743
744 if (item->GetWindow() == window)
745 {
89c20ac1 746 delete item;
222ed1d6
MB
747 m_children.Erase( node );
748 return true;
00976fe5 749 }
12a3f227 750 node = node->GetNext();
00976fe5
RL
751 }
752
e0d8fb45 753 return false;
00976fe5
RL
754}
755
e0d8fb45 756bool wxSizer::Detach( int index )
00976fe5 757{
e0d8fb45
VZ
758 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
759 false,
12a3f227
RL
760 _T("Detach index is out of range") );
761
222ed1d6 762 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
00976fe5 763
e0d8fb45 764 wxCHECK_MSG( node, false, _T("Failed to find child node") );
00976fe5 765
e0d8fb45 766 wxSizerItem *item = node->GetData();
9cbee2ce 767
50c06297 768 if ( item->IsSizer() )
9cbee2ce 769 item->DetachSizer();
12a3f227 770
89c20ac1 771 delete item;
222ed1d6
MB
772 m_children.Erase( node );
773 return true;
00976fe5
RL
774}
775
eae0338f
RR
776bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
777{
778 wxASSERT_MSG( oldwin, _T("Replacing NULL window") );
779 wxASSERT_MSG( newwin, _T("Replacing with NULL window") );
780
781 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
782 while (node)
783 {
784 wxSizerItem *item = node->GetData();
785
786 if (item->GetWindow() == oldwin)
787 {
a50cf60e 788 item->AssignWindow(newwin);
eae0338f
RR
789 newwin->SetContainingSizer( this );
790 return true;
791 }
792 else if (recursive && item->IsSizer())
793 {
794 if (item->GetSizer()->Replace( oldwin, newwin, true ))
795 return true;
796 }
e8cfff87 797
eae0338f
RR
798 node = node->GetNext();
799 }
800
801 return false;
802}
803
804bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive )
805{
806 wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") );
807 wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") );
808
809 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
810 while (node)
811 {
812 wxSizerItem *item = node->GetData();
813
814 if (item->GetSizer() == oldsz)
815 {
a50cf60e 816 item->AssignSizer(newsz);
eae0338f
RR
817 return true;
818 }
819 else if (recursive && item->IsSizer())
820 {
821 if (item->GetSizer()->Replace( oldsz, newsz, true ))
822 return true;
e8cfff87
VZ
823 }
824
eae0338f
RR
825 node = node->GetNext();
826 }
827
828 return false;
829}
830
831bool wxSizer::Replace( size_t old, wxSizerItem *newitem )
832{
833 wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") );
834 wxASSERT_MSG( newitem, _T("Replacing with NULL item") );
835
836 wxSizerItemList::compatibility_iterator node = m_children.Item( old );
837
838 wxCHECK_MSG( node, false, _T("Failed to find child node") );
839
840 wxSizerItem *item = node->GetData();
841 node->SetData(newitem);
e8cfff87 842 delete item;
eae0338f
RR
843
844 return true;
845}
846
84f7908b
RR
847void wxSizer::Clear( bool delete_windows )
848{
be90c029 849 // First clear the ContainingSizer pointers
222ed1d6 850 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
be90c029
RD
851 while (node)
852 {
12a3f227
RL
853 wxSizerItem *item = node->GetData();
854
be90c029 855 if (item->IsWindow())
12a3f227
RL
856 item->GetWindow()->SetContainingSizer( NULL );
857 node = node->GetNext();
be90c029
RD
858 }
859
860 // Destroy the windows if needed
84f7908b
RR
861 if (delete_windows)
862 DeleteWindows();
be90c029
RD
863
864 // Now empty the list
222ed1d6 865 WX_CLEAR_LIST(wxSizerItemList, m_children);
84f7908b
RR
866}
867
868void wxSizer::DeleteWindows()
869{
222ed1d6 870 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
84f7908b
RR
871 while (node)
872 {
12a3f227
RL
873 wxSizerItem *item = node->GetData();
874
84f7908b 875 item->DeleteWindows();
12a3f227 876 node = node->GetNext();
84f7908b
RR
877 }
878}
879
32013b47 880wxSize wxSizer::ComputeFittingClientSize(wxWindow *window)
5279a24d 881{
32013b47
VS
882 wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
883
98018a4b 884 // take the min size by default and limit it by max size
02dc0099 885 wxSize size = GetMinClientSize(window);
7e7bc14b 886 wxSize sizeMax;
98018a4b
VZ
887
888 wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
889 if ( tlw )
890 {
891 // hack for small screen devices where TLWs are always full screen
892 if ( tlw->IsAlwaysMaximized() )
893 {
32013b47 894 return tlw->GetClientSize();
98018a4b 895 }
7e7bc14b 896
c30199bf
RR
897 // limit the window to the size of the display it is on
898 int disp = wxDisplay::GetFromWindow(window);
899 if ( disp == wxNOT_FOUND )
98018a4b 900 {
c30199bf
RR
901 // or, if we don't know which one it is, of the main one
902 disp = 0;
98018a4b 903 }
9ef2e675 904
7e7bc14b
VS
905 sizeMax = wxDisplay(disp).GetClientArea().GetSize();
906
c30199bf 907 // space for decorations and toolbars etc.
77fe7204 908 sizeMax = tlw->WindowToClientSize(sizeMax);
c30199bf
RR
909 }
910 else
911 {
7e7bc14b 912 sizeMax = GetMaxClientSize(window);
c30199bf 913 }
7e7bc14b
VS
914
915 if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
916 size.x = sizeMax.x;
917 if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
918 size.y = sizeMax.y;
919
32013b47
VS
920 return size;
921}
922
923wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window)
924{
925 wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
926
927 return window->ClientToWindowSize(ComputeFittingClientSize(window));
928}
929
930wxSize wxSizer::Fit( wxWindow *window )
931{
932 wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
933
7e7bc14b 934 // set client size
32013b47 935 window->SetClientSize(ComputeFittingClientSize(window));
7e7bc14b
VS
936
937 // return entire size
938 return window->GetSize();
5279a24d
RR
939}
940
566d84a7
RL
941void wxSizer::FitInside( wxWindow *window )
942{
943 wxSize size;
944 if (window->IsTopLevel())
945 size = VirtualFitSize( window );
946 else
947 size = GetMinClientSize( window );
948
949 window->SetVirtualSize( size );
950}
951
3417c2cd 952void wxSizer::Layout()
c62ac5b6 953{
ba763a45
RD
954 // (re)calculates minimums needed for each item and other preparations
955 // for layout
42b4e99e 956 CalcMin();
ba763a45
RD
957
958 // Applies the layout and repositions/resizes the items
c62ac5b6
RR
959 RecalcSizes();
960}
961
3417c2cd 962void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 963{
34c3ffca
RL
964 // Preserve the window's max size hints, but set the
965 // lower bound according to the sizer calculations.
966
428c07c0
VS
967 // This is equivalent to calling Fit(), except that we need to set
968 // the size hints _in between_ the two steps performed by Fit
969 // (1. ComputeFittingClientSize, 2. SetClientSize). That's because
970 // otherwise SetClientSize() could have no effect if there already are
971 // size hints in effect that forbid requested client size.
e5251d4f 972
428c07c0
VS
973 const wxSize clientSize = ComputeFittingClientSize(window);
974
975 window->SetMinClientSize(clientSize);
976 window->SetClientSize(clientSize);
5279a24d
RR
977}
978
f944aec0 979#if WXWIN_COMPATIBILITY_2_8
566d84a7
RL
980void wxSizer::SetVirtualSizeHints( wxWindow *window )
981{
566d84a7 982 FitInside( window );
566d84a7 983}
f944aec0 984#endif // WXWIN_COMPATIBILITY_2_8
566d84a7 985
e11d436b
SC
986// TODO on mac we need a function that determines how much free space this
987// min size contains, in order to make sure that we have 20 pixels of free
988// space around the controls
9cbee2ce 989wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7 990{
77fe7204 991 return window->WindowToClientSize(window->GetMaxSize());
566d84a7
RL
992}
993
1b0674f7 994wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
995{
996 return GetMinSize(); // Already returns client size.
997}
998
999wxSize wxSizer::VirtualFitSize( wxWindow *window )
1000{
1001 wxSize size = GetMinClientSize( window );
1002 wxSize sizeMax = GetMaxClientSize( window );
1003
1004 // Limit the size if sizeMax != wxDefaultSize
1005
d775fa82 1006 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
566d84a7 1007 size.x = sizeMax.x;
d775fa82 1008 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
566d84a7
RL
1009 size.y = sizeMax.y;
1010
1011 return size;
1012}
1013
f6bcfd97 1014wxSize wxSizer::GetMinSize()
3ca6a5f0 1015{
f6bcfd97
BP
1016 wxSize ret( CalcMin() );
1017 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
1018 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 1019 return ret;
f6bcfd97
BP
1020}
1021
1022void wxSizer::DoSetMinSize( int width, int height )
1023{
1024 m_minSize.x = width;
1025 m_minSize.y = height;
1026}
1027
1028bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
1029{
12a3f227
RL
1030 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
1031
1032 // Is it our immediate child?
f6bcfd97 1033
222ed1d6 1034 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1035 while (node)
1036 {
12a3f227
RL
1037 wxSizerItem *item = node->GetData();
1038
3ca6a5f0
BP
1039 if (item->GetWindow() == window)
1040 {
1eba2193 1041 item->SetMinSize( width, height );
e0d8fb45 1042 return true;
3ca6a5f0 1043 }
12a3f227 1044 node = node->GetNext();
f6bcfd97
BP
1045 }
1046
12a3f227
RL
1047 // No? Search any subsizers we own then
1048
1049 node = m_children.GetFirst();
f6bcfd97
BP
1050 while (node)
1051 {
12a3f227
RL
1052 wxSizerItem *item = node->GetData();
1053
1054 if ( item->GetSizer() &&
1055 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 1056 {
12a3f227 1057 // A child sizer found the requested windw, exit.
e0d8fb45 1058 return true;
3ca6a5f0 1059 }
12a3f227 1060 node = node->GetNext();
f6bcfd97
BP
1061 }
1062
e0d8fb45 1063 return false;
f6bcfd97
BP
1064}
1065
1066bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
1067{
12a3f227 1068 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 1069
12a3f227
RL
1070 // Is it our immediate child?
1071
222ed1d6 1072 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1073 while (node)
1074 {
12a3f227
RL
1075 wxSizerItem *item = node->GetData();
1076
3ca6a5f0
BP
1077 if (item->GetSizer() == sizer)
1078 {
f6bcfd97 1079 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 1080 return true;
3ca6a5f0 1081 }
12a3f227 1082 node = node->GetNext();
f6bcfd97
BP
1083 }
1084
12a3f227
RL
1085 // No? Search any subsizers we own then
1086
1087 node = m_children.GetFirst();
f6bcfd97
BP
1088 while (node)
1089 {
12a3f227
RL
1090 wxSizerItem *item = node->GetData();
1091
1092 if ( item->GetSizer() &&
1093 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 1094 {
12a3f227 1095 // A child found the requested sizer, exit.
e0d8fb45 1096 return true;
3ca6a5f0 1097 }
12a3f227 1098 node = node->GetNext();
f6bcfd97
BP
1099 }
1100
e0d8fb45 1101 return false;
f6bcfd97
BP
1102}
1103
12a3f227 1104bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 1105{
222ed1d6 1106 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
12a3f227 1107
e0d8fb45 1108 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
1109
1110 wxSizerItem *item = node->GetData();
f6bcfd97 1111
f6bcfd97
BP
1112 if (item->GetSizer())
1113 {
0ca5105b 1114 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
1115 item->GetSizer()->DoSetMinSize( width, height );
1116 }
1117 else
1118 {
ba763a45 1119 // ... but the minimal size of spacers and windows is stored via the item
1eba2193 1120 item->SetMinSize( width, height );
f6bcfd97
BP
1121 }
1122
e0d8fb45 1123 return true;
f6bcfd97
BP
1124}
1125
9f13661f 1126wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
2b5f62a0 1127{
9f13661f 1128 wxASSERT_MSG( window, _T("GetItem for NULL window") );
12a3f227 1129
222ed1d6 1130 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1131 while (node)
1132 {
12a3f227 1133 wxSizerItem *item = node->GetData();
2b5f62a0 1134
12a3f227 1135 if (item->GetWindow() == window)
2b5f62a0 1136 {
9f13661f 1137 return item;
2b5f62a0 1138 }
8b2bac62
WS
1139 else if (recursive && item->IsSizer())
1140 {
9f13661f
WS
1141 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
1142 if (subitem)
1143 return subitem;
8b2bac62
WS
1144 }
1145
12a3f227 1146 node = node->GetNext();
2b5f62a0 1147 }
8b2bac62 1148
9f13661f 1149 return NULL;
2b5f62a0
VZ
1150}
1151
9f13661f 1152wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
2b5f62a0 1153{
9f13661f 1154 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
12a3f227 1155
222ed1d6 1156 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1157 while (node)
1158 {
9f13661f 1159 wxSizerItem *item = node->GetData();
2b5f62a0 1160
12a3f227 1161 if (item->GetSizer() == sizer)
2b5f62a0 1162 {
9f13661f 1163 return item;
2b5f62a0 1164 }
8b2bac62
WS
1165 else if (recursive && item->IsSizer())
1166 {
9f13661f
WS
1167 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
1168 if (subitem)
1169 return subitem;
8b2bac62
WS
1170 }
1171
12a3f227 1172 node = node->GetNext();
2b5f62a0 1173 }
8b2bac62 1174
9f13661f
WS
1175 return NULL;
1176}
1177
1178wxSizerItem* wxSizer::GetItem( size_t index )
1179{
1180 wxCHECK_MSG( index < m_children.GetCount(),
1181 NULL,
1182 _T("GetItem index is out of range") );
1183
1184 return m_children.Item( index )->GetData();
1185}
1186
86909f4c
VZ
1187wxSizerItem* wxSizer::GetItemById( int id, bool recursive )
1188{
1189 // This gets a sizer item by the id of the sizer item
1190 // and NOT the id of a window if the item is a window.
1191
1192 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1193 while (node)
1194 {
1195 wxSizerItem *item = node->GetData();
1196
1197 if (item->GetId() == id)
1198 {
1199 return item;
1200 }
1201 else if (recursive && item->IsSizer())
1202 {
1203 wxSizerItem *subitem = item->GetSizer()->GetItemById( id, true );
1204 if (subitem)
1205 return subitem;
1206 }
1207
1208 node = node->GetNext();
1209 }
1210
1211 return NULL;
1212}
1213
9f13661f
WS
1214bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
1215{
1216 wxSizerItem *item = GetItem( window, recursive );
1217
1218 if ( item )
1219 {
1220 item->Show( show );
1221 return true;
1222 }
1223
1224 return false;
1225}
1226
1227bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
1228{
1229 wxSizerItem *item = GetItem( sizer, recursive );
1230
1231 if ( item )
1232 {
1233 item->Show( show );
1234 return true;
1235 }
1236
8b2bac62 1237 return false;
2b5f62a0
VZ
1238}
1239
8b2bac62 1240bool wxSizer::Show( size_t index, bool show)
2b5f62a0 1241{
9f13661f 1242 wxSizerItem *item = GetItem( index );
2b5f62a0 1243
9f13661f
WS
1244 if ( item )
1245 {
1246 item->Show( show );
1247 return true;
1248 }
8b2bac62 1249
9f13661f 1250 return false;
12a3f227 1251}
2b5f62a0 1252
12a3f227
RL
1253void wxSizer::ShowItems( bool show )
1254{
222ed1d6 1255 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
1256 while (node)
1257 {
1258 node->GetData()->Show( show );
1259 node = node->GetNext();
2b5f62a0
VZ
1260 }
1261}
1262
9cbee2ce 1263bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 1264{
222ed1d6 1265 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1266 while (node)
1267 {
12a3f227 1268 wxSizerItem *item = node->GetData();
dc259b79 1269
12a3f227 1270 if (item->GetWindow() == window)
2b5f62a0
VZ
1271 {
1272 return item->IsShown();
1273 }
12a3f227 1274 node = node->GetNext();
2b5f62a0
VZ
1275 }
1276
12a3f227
RL
1277 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1278
e0d8fb45 1279 return false;
2b5f62a0
VZ
1280}
1281
9cbee2ce 1282bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 1283{
222ed1d6 1284 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
1285 while (node)
1286 {
12a3f227 1287 wxSizerItem *item = node->GetData();
2b5f62a0 1288
12a3f227 1289 if (item->GetSizer() == sizer)
2b5f62a0
VZ
1290 {
1291 return item->IsShown();
1292 }
12a3f227 1293 node = node->GetNext();
2b5f62a0
VZ
1294 }
1295
12a3f227
RL
1296 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1297
e0d8fb45 1298 return false;
2b5f62a0
VZ
1299}
1300
9cbee2ce 1301bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
1302{
1303 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 1304 false,
12a3f227
RL
1305 _T("IsShown index is out of range") );
1306
1307 return m_children.Item( index )->GetData()->IsShown();
1308}
1309
1310
f6bcfd97
BP
1311//---------------------------------------------------------------------------
1312// wxGridSizer
1313//---------------------------------------------------------------------------
1314
1315wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
902725ee 1316 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
12a3f227
RL
1317 , m_cols( cols )
1318 , m_vgap( vgap )
1319 , m_hgap( hgap )
f6bcfd97 1320{
f6bcfd97
BP
1321}
1322
1323wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
902725ee 1324 : m_rows( cols == 0 ? 1 : 0 )
12a3f227
RL
1325 , m_cols( cols )
1326 , m_vgap( vgap )
1327 , m_hgap( hgap )
f6bcfd97 1328{
f6bcfd97
BP
1329}
1330
0ca5105b 1331int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 1332{
5fa51d09 1333 const int nitems = m_children.GetCount();
6115b1b5 1334 if ( m_cols && m_rows )
0ca5105b 1335 {
6115b1b5 1336 // if both rows and columns are specified by user, use the provided
2283800b
VZ
1337 // values even if we don't have enough items but check that we don't
1338 // have too many of them as this is going to result in problems later
6115b1b5
VZ
1339 ncols = m_cols;
1340 nrows = m_rows;
2283800b 1341
636a53b3 1342 wxASSERT_MSG( ncols*nrows >= nitems, "too many items in grid sizer" );
6115b1b5
VZ
1343 }
1344 else if ( m_cols )
1345 {
1346 ncols = m_cols;
1347 nrows = (nitems + m_cols - 1) / m_cols;
1348 }
1349 else if ( m_rows )
1350 {
1351 ncols = (nitems + m_rows - 1) / m_rows;
1352 nrows = m_rows;
1353 }
1354 else // 0 columns, 0 rows?
1355 {
1356 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 1357
6115b1b5
VZ
1358 nrows =
1359 ncols = 0;
0ca5105b
VZ
1360 }
1361
1362 return nitems;
1363}
1364
1365void wxGridSizer::RecalcSizes()
1366{
1367 int nitems, nrows, ncols;
1368 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1369 return;
f6bcfd97
BP
1370
1371 wxSize sz( GetSize() );
1372 wxPoint pt( GetPosition() );
3ca6a5f0
BP
1373
1374 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1375 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
1376
1377 int x = pt.x;
1378 for (int c = 0; c < ncols; c++)
1379 {
1380 int y = pt.y;
1381 for (int r = 0; r < nrows; r++)
1382 {
1383 int i = r * ncols + c;
1384 if (i < nitems)
1385 {
222ed1d6 1386 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1387
1388 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 1389
12a3f227 1390 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1391 }
1392 y = y + h + m_vgap;
1393 }
1394 x = x + w + m_hgap;
1395 }
1396}
1397
1398wxSize wxGridSizer::CalcMin()
1399{
196be0f1
JS
1400 int nrows, ncols;
1401 if ( CalcRowsCols(nrows, ncols) == 0 )
b3f1734f 1402 return wxSize();
f6bcfd97 1403
4f469fb5 1404 // Find the max width and height for any component
f6bcfd97
BP
1405 int w = 0;
1406 int h = 0;
3ca6a5f0 1407
222ed1d6 1408 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1409 while (node)
1410 {
12a3f227
RL
1411 wxSizerItem *item = node->GetData();
1412 wxSize sz( item->CalcMin() );
1413
f6bcfd97
BP
1414 w = wxMax( w, sz.x );
1415 h = wxMax( h, sz.y );
3ca6a5f0 1416
12a3f227 1417 node = node->GetNext();
f6bcfd97 1418 }
3ca6a5f0 1419
3d2085a4 1420 // In case we have a nested sizer with a two step algo , give it
15f7c305
RR
1421 // a chance to adjust to that (we give it width component)
1422 node = m_children.GetFirst();
1423 bool didChangeMinSize = false;
1424 while (node)
1425 {
1426 wxSizerItem *item = node->GetData();
1427 didChangeMinSize |= item->InformFirstDirection( wxHORIZONTAL, w, -1 );
3d2085a4 1428
15f7c305
RR
1429 node = node->GetNext();
1430 }
3d2085a4 1431
15f7c305
RR
1432 // And redo iteration in case min size changed
1433 if( didChangeMinSize )
1434 {
1435 node = m_children.GetFirst();
1436 w = h = 0;
1437 while (node)
1438 {
1439 wxSizerItem *item = node->GetData();
1440 wxSize sz( item->GetMinSizeWithBorder() );
1441
1442 w = wxMax( w, sz.x );
1443 h = wxMax( h, sz.y );
1444
1445 node = node->GetNext();
3d2085a4 1446 }
15f7c305 1447 }
3d2085a4 1448
12a3f227
RL
1449 return wxSize( ncols * w + (ncols-1) * m_hgap,
1450 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
1451}
1452
1453void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1454{
1455 wxPoint pt( x,y );
8b2bac62 1456 wxSize sz( item->GetMinSizeWithBorder() );
f6bcfd97
BP
1457 int flag = item->GetFlag();
1458
1459 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1460 {
1461 sz = wxSize(w, h);
1462 }
1463 else
1464 {
1465 if (flag & wxALIGN_CENTER_HORIZONTAL)
1466 {
559b747d 1467 pt.x = x + (w - sz.x) / 2;
f6bcfd97
BP
1468 }
1469 else if (flag & wxALIGN_RIGHT)
1470 {
559b747d 1471 pt.x = x + (w - sz.x);
f6bcfd97 1472 }
3ca6a5f0 1473
f6bcfd97
BP
1474 if (flag & wxALIGN_CENTER_VERTICAL)
1475 {
559b747d 1476 pt.y = y + (h - sz.y) / 2;
f6bcfd97
BP
1477 }
1478 else if (flag & wxALIGN_BOTTOM)
1479 {
559b747d 1480 pt.y = y + (h - sz.y);
f6bcfd97
BP
1481 }
1482 }
3ca6a5f0 1483
f6bcfd97
BP
1484 item->SetDimension(pt, sz);
1485}
1486
1487//---------------------------------------------------------------------------
1488// wxFlexGridSizer
1489//---------------------------------------------------------------------------
1490
1491wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1492 : wxGridSizer( rows, cols, vgap, hgap ),
1493 m_flexDirection(wxBOTH),
1494 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1495{
f6bcfd97
BP
1496}
1497
1498wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1499 : wxGridSizer( cols, vgap, hgap ),
1500 m_flexDirection(wxBOTH),
1501 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1502{
f6bcfd97 1503}
3ca6a5f0 1504
f6bcfd97
BP
1505wxFlexGridSizer::~wxFlexGridSizer()
1506{
f6bcfd97
BP
1507}
1508
1509void wxFlexGridSizer::RecalcSizes()
1510{
74ab5f5b
VZ
1511 int nrows, ncols;
1512 if ( !CalcRowsCols(nrows, ncols) )
f6bcfd97
BP
1513 return;
1514
97800f66
VZ
1515 const wxPoint pt(GetPosition());
1516 const wxSize sz(GetSize());
3ca6a5f0 1517
97800f66 1518 AdjustForGrowables(sz);
f6bcfd97 1519
97800f66 1520 wxSizerItemList::const_iterator i = m_children.begin();
cc67d082
VZ
1521 const wxSizerItemList::const_iterator end = m_children.end();
1522
97800f66
VZ
1523 int y = 0;
1524 for ( int r = 0; r < nrows; r++ )
f6bcfd97 1525 {
97800f66 1526 if ( m_rowHeights[r] == -1 )
f6bcfd97 1527 {
97800f66
VZ
1528 // this row is entirely hidden, skip it
1529 for ( int c = 0; c < ncols; c++ )
cc67d082
VZ
1530 {
1531 if ( i == end )
1532 return;
1533
97800f66 1534 ++i;
cc67d082 1535 }
12a3f227 1536
97800f66
VZ
1537 continue;
1538 }
3ca6a5f0 1539
97800f66
VZ
1540 const int hrow = m_rowHeights[r];
1541 int h = sz.y - y; // max remaining height, don't overflow it
1542 if ( hrow < h )
1543 h = hrow;
3ca6a5f0 1544
97800f66 1545 int x = 0;
cc67d082 1546 for ( int c = 0; c < ncols && i != end; c++, ++i )
97800f66
VZ
1547 {
1548 const int wcol = m_colWidths[c];
1549
1550 if ( wcol == -1 )
1551 continue;
1552
97800f66
VZ
1553 int w = sz.x - x; // max possible value, ensure we don't overflow
1554 if ( wcol < w )
1555 w = wcol;
1556
1557 SetItemBounds(*i, pt.x + x, pt.y + y, w, h);
1558
1559 x += wcol + m_hgap;
f6bcfd97 1560 }
97800f66 1561
cc67d082
VZ
1562 if ( i == end )
1563 return;
1564
97800f66 1565 y += hrow + m_vgap;
f6bcfd97
BP
1566 }
1567}
1568
97800f66
VZ
1569// helper function used in CalcMin() to sum up the sizes of non-hidden items
1570static int SumArraySizes(const wxArrayInt& sizes, int gap)
1571{
1572 // Sum total minimum size, including gaps between rows/columns.
1573 // -1 is used as a magic number meaning empty row/column.
1574 int total = 0;
1575
1576 const size_t count = sizes.size();
1577 for ( size_t n = 0; n < count; n++ )
1578 {
1579 if ( sizes[n] != -1 )
1580 {
1581 if ( total )
1582 total += gap; // separate from the previous column
1583
1584 total += sizes[n];
1585 }
1586 }
1587
1588 return total;
1589}
1590
15f7c305 1591void wxFlexGridSizer::FindWidthsAndHeights(int nrows, int ncols)
f6bcfd97 1592{
97800f66 1593 // We have to recalculate the sizes in case the item minimum size has
395a82b1
VZ
1594 // changed since the previous layout, or the item has been hidden using
1595 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1596 // dimension of the row/column will be -1, indicating that the column
1597 // itself is hidden.
97800f66
VZ
1598 m_rowHeights.assign(nrows, -1);
1599 m_colWidths.assign(ncols, -1);
1600
1601 // n is the index of the item in left-to-right top-to-bottom order
1602 size_t n = 0;
1603 for ( wxSizerItemList::iterator i = m_children.begin();
1604 i != m_children.end();
1605 ++i, ++n )
f6bcfd97 1606 {
97800f66 1607 wxSizerItem * const item = *i;
55f9f0cb
VZ
1608 if ( item->IsShown() )
1609 {
3d2085a4 1610 // NOTE: Not doing the calculation here, this is just
15f7c305
RR
1611 // for finding max values.
1612 const wxSize sz(item->GetMinSizeWithBorder());
12a3f227 1613
97800f66
VZ
1614 const int row = n / ncols;
1615 const int col = n % ncols;
3ca6a5f0 1616
97800f66
VZ
1617 if ( sz.y > m_rowHeights[row] )
1618 m_rowHeights[row] = sz.y;
1619 if ( sz.x > m_colWidths[col] )
1620 m_colWidths[col] = sz.x;
1621 }
f6bcfd97 1622 }
3ca6a5f0 1623
20b35a69 1624 AdjustForFlexDirection();
8b2bac62 1625
97800f66
VZ
1626 m_calculatedMinSize = wxSize(SumArraySizes(m_colWidths, m_hgap),
1627 SumArraySizes(m_rowHeights, m_vgap));
15f7c305
RR
1628}
1629
1630wxSize wxFlexGridSizer::CalcMin()
1631{
1632 int nrows,
1633 ncols;
1634
1635 // Number of rows/columns can change as items are added or removed.
1636 if ( !CalcRowsCols(nrows, ncols) )
1637 return wxSize();
1638
1639
1640 // We have to recalculate the sizes in case the item minimum size has
1641 // changed since the previous layout, or the item has been hidden using
1642 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1643 // dimension of the row/column will be -1, indicating that the column
1644 // itself is hidden.
1645 m_rowHeights.assign(nrows, -1);
1646 m_colWidths.assign(ncols, -1);
1647
15f7c305
RR
1648 for ( wxSizerItemList::iterator i = m_children.begin();
1649 i != m_children.end();
b7bc9d80 1650 ++i)
15f7c305
RR
1651 {
1652 wxSizerItem * const item = *i;
1653 if ( item->IsShown() )
1654 {
1655 item->CalcMin();
1656 }
1657 }
1658
3d2085a4 1659 // The stage of looking for max values in each row/column has been
15f7c305
RR
1660 // made a separate function, since it's reused in AdjustForGrowables.
1661 FindWidthsAndHeights(nrows,ncols);
97800f66 1662
ba763a45 1663 return m_calculatedMinSize;
20b35a69
RD
1664}
1665
1666void wxFlexGridSizer::AdjustForFlexDirection()
1667{
1668 // the logic in CalcMin works when we resize flexibly in both directions
1669 // but maybe this is not the case
5d76f462
VZ
1670 if ( m_flexDirection != wxBOTH )
1671 {
1672 // select the array corresponding to the direction in which we do *not*
1673 // resize flexibly
1674 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1675 : m_rowHeights;
1676
4a10ea8b 1677 const size_t count = array.GetCount();
5d76f462
VZ
1678
1679 // find the largest value in this array
4a10ea8b
MW
1680 size_t n;
1681 int largest = 0;
1682
5d76f462
VZ
1683 for ( n = 0; n < count; ++n )
1684 {
1685 if ( array[n] > largest )
1686 largest = array[n];
1687 }
1688
1689 // and now fill it with the largest value
1690 for ( n = 0; n < count; ++n )
1691 {
b9a325a1
VZ
1692 // don't touch hidden rows
1693 if ( array[n] != -1 )
1694 array[n] = largest;
5d76f462
VZ
1695 }
1696 }
8b2bac62 1697}
5d76f462 1698
97800f66
VZ
1699// helper of AdjustForGrowables() which is called for rows/columns separately
1700//
1701// parameters:
1702// delta: the extra space, we do nothing unless it's positive
1703// growable: indices or growable rows/cols in sizes array
1704// sizes: the height/widths of rows/cols to adjust
1705// proportions: proportions of the growable rows/cols or NULL if they all
1706// should be assumed to have proportion of 1
1707static void
1708DoAdjustForGrowables(int delta,
1709 const wxArrayInt& growable,
1710 wxArrayInt& sizes,
1711 const wxArrayInt *proportions)
1712{
1713 if ( delta <= 0 )
1714 return;
3ca6a5f0 1715
97800f66
VZ
1716 // total sum of proportions of all non-hidden rows
1717 int sum_proportions = 0;
8b2bac62 1718
97800f66
VZ
1719 // number of currently shown growable rows
1720 int num = 0;
3ca6a5f0 1721
97800f66
VZ
1722 const int max_idx = sizes.size();
1723
1724 const size_t count = growable.size();
1725 size_t idx;
1726 for ( idx = 0; idx < count; idx++ )
20b35a69 1727 {
97800f66
VZ
1728 // Since the number of rows/columns can change as items are
1729 // inserted/deleted, we need to verify at runtime that the
1730 // requested growable rows/columns are still valid.
1731 if ( growable[idx] >= max_idx )
1732 continue;
1733
1734 // If all items in a row/column are hidden, that row/column will
1735 // have a dimension of -1. This causes the row/column to be
1736 // hidden completely.
1737 if ( sizes[growable[idx]] == -1 )
1738 continue;
1739
1740 if ( proportions )
1741 sum_proportions += (*proportions)[idx];
1742
1743 num++;
20b35a69
RD
1744 }
1745
97800f66
VZ
1746 if ( !num )
1747 return;
1748
1749 // the remaining extra free space, adjusted during each iteration
1750 for ( idx = 0; idx < count; idx++ )
20b35a69 1751 {
97800f66
VZ
1752 if ( growable[idx] >= max_idx )
1753 continue;
8b2bac62 1754
97800f66
VZ
1755 if ( sizes[ growable[idx] ] == -1 )
1756 continue;
20b35a69 1757
97800f66
VZ
1758 int cur_delta;
1759 if ( sum_proportions == 0 )
20b35a69 1760 {
97800f66
VZ
1761 // no growable rows -- divide extra space evenly among all
1762 cur_delta = delta/num;
1763 num--;
20b35a69 1764 }
97800f66
VZ
1765 else // allocate extra space proportionally
1766 {
1767 const int cur_prop = (*proportions)[idx];
1768 cur_delta = (delta*cur_prop)/sum_proportions;
1769 sum_proportions -= cur_prop;
1770 }
1771
1772 sizes[growable[idx]] += cur_delta;
1773 delta -= cur_delta;
20b35a69 1774 }
97800f66
VZ
1775}
1776
1777void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
1778{
15f7c305 1779 if ( (m_flexDirection & wxHORIZONTAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
97800f66 1780 {
97800f66
VZ
1781 DoAdjustForGrowables
1782 (
15f7c305
RR
1783 sz.x - m_calculatedMinSize.x,
1784 m_growableCols,
1785 m_colWidths,
1786 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
97800f66
VZ
1787 : NULL
1788 );
3d2085a4
VZ
1789
1790 // This gives nested objects that benefit from knowing one size
1791 // component in advance the chance to use that.
15f7c305
RR
1792 bool didAdjustMinSize = false;
1793 int nrows, ncols;
1794 CalcRowsCols(nrows, ncols);
3d2085a4 1795
15f7c305
RR
1796 // Iterate over all items and inform about column width
1797 size_t n = 0;
1798 for ( wxSizerItemList::iterator i = m_children.begin();
1799 i != m_children.end();
1800 ++i, ++n )
1801 {
1802 const int col = n % ncols;
1803 didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
b7bc9d80 1804 }
97800f66 1805
3d2085a4 1806 // Only redo if info was actually used
15f7c305 1807 if( didAdjustMinSize )
b7bc9d80
PC
1808 {
1809 DoAdjustForGrowables
1810 (
1811 sz.x - m_calculatedMinSize.x,
1812 m_growableCols,
1813 m_colWidths,
1814 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
1815 : NULL
1816 );
1817 }
20b35a69 1818 }
f6bcfd97 1819
15f7c305
RR
1820 if ( (m_flexDirection & wxVERTICAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
1821 {
1822 // pass NULL instead of proportions if the grow mode is ALL as we
1823 // should treat all rows as having proportion of 1 then
1824 DoAdjustForGrowables
1825 (
1826 sz.y - m_calculatedMinSize.y,
1827 m_growableRows,
1828 m_rowHeights,
1829 m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableRowsProportions
1830 : NULL
1831 );
1832 }
1833}
1834
67ef83eb
VZ
1835bool wxFlexGridSizer::IsRowGrowable( size_t idx )
1836{
1837 return m_growableRows.Index( idx ) != wxNOT_FOUND;
1838}
1839
1840bool wxFlexGridSizer::IsColGrowable( size_t idx )
1841{
1842 return m_growableCols.Index( idx ) != wxNOT_FOUND;
1843}
20b35a69 1844
e8800dcf 1845void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97 1846{
324dc1f2
VZ
1847 int nrows, ncols;
1848 CalcRowsCols(nrows, ncols);
1849 wxCHECK_RET( idx < (size_t)nrows, "invalid row index" );
1850
ef52f19e 1851 wxASSERT_MSG( !IsRowGrowable( idx ),
67ef83eb 1852 "AddGrowableRow() called for growable row" );
f6bcfd97 1853 m_growableRows.Add( idx );
e8800dcf 1854 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1855}
1856
e8800dcf 1857void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97 1858{
324dc1f2
VZ
1859 int nrows, ncols;
1860 CalcRowsCols(nrows, ncols);
1861 wxCHECK_RET( idx < (size_t)ncols, "invalid column index" );
1862
ef52f19e 1863 wxASSERT_MSG( !IsColGrowable( idx ),
67ef83eb 1864 "AddGrowableCol() called for growable column" );
f6bcfd97 1865 m_growableCols.Add( idx );
e8800dcf 1866 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1867}
1868
ca243008
VZ
1869// helper function for RemoveGrowableCol/Row()
1870static void
1871DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1872{
1873 const size_t count = items.size();
1874 for ( size_t n = 0; n < count; n++ )
1875 {
1876 if ( (size_t)items[n] == idx )
1877 {
1878 items.RemoveAt(n);
1879 proportions.RemoveAt(n);
1880 return;
1881 }
1882 }
1883
1884 wxFAIL_MSG( _T("column/row is already not growable") );
1885}
1886
8d2474f4 1887void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
f6bcfd97 1888{
ca243008
VZ
1889 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1890}
1891
1892void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1893{
1894 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
f6bcfd97
BP
1895}
1896
c62ac5b6 1897//---------------------------------------------------------------------------
92afa2b1 1898// wxBoxSizer
61d514bb
RR
1899//---------------------------------------------------------------------------
1900
92afa2b1 1901void wxBoxSizer::RecalcSizes()
61d514bb 1902{
89064717 1903 if ( m_children.empty() )
61d514bb 1904 return;
0c0d686f 1905
3d2085a4 1906 const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
15f7c305 1907
89064717
VZ
1908 // the amount of free space which we should redistribute among the
1909 // stretchable items (i.e. those with non zero proportion)
3d2085a4
VZ
1910 int delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1911
0c0d686f 1912
15f7c305
RR
1913 // Inform child items about the size in minor direction, that can
1914 // change how much free space we have in major dir and how to distribute it.
1915 int majorMinSum = 0;
82287aae
CE
1916 wxSizerItemList::const_iterator i ;
1917 for ( i = m_children.begin();
15f7c305
RR
1918 i != m_children.end();
1919 ++i )
1920 {
1921 wxSizerItem * const item = *i;
1922
1923 if ( !item->IsShown() )
1924 continue;
1925
1926 wxSize szMinPrev = item->GetMinSizeWithBorder();
1927 item->InformFirstDirection(m_orient^wxBOTH,totalMinorSize,delta);
1928 wxSize szMin = item->GetMinSizeWithBorder();
3d2085a4 1929 int deltaChange = GetSizeInMajorDir(szMin-szMinPrev);
15f7c305
RR
1930 if( deltaChange )
1931 {
3d2085a4
VZ
1932 // Since we passed available space along to the item, it should not
1933 // take too much, so delta should not become negative.
1934 delta -= deltaChange;
15f7c305 1935 }
3d2085a4 1936 majorMinSum += GetSizeInMajorDir(item->GetMinSizeWithBorder());
15f7c305
RR
1937 }
1938 // And update our min size
1939 SizeInMajorDir(m_minSize) = majorMinSum;
1940
1941
1942 // might have a new delta now
3d2085a4
VZ
1943 delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1944
89064717
VZ
1945 // the position at which we put the next child
1946 wxPoint pt(m_position);
12a3f227 1947
7fca7a73 1948 int totalProportion = m_totalProportion;
82287aae 1949 for ( i = m_children.begin();
89064717
VZ
1950 i != m_children.end();
1951 ++i )
1952 {
1953 wxSizerItem * const item = *i;
2b5f62a0 1954
89064717
VZ
1955 if ( !item->IsShown() )
1956 continue;
3d2085a4
VZ
1957
1958 const wxSize sizeThis(item->GetMinSizeWithBorder());
2b5f62a0 1959
89064717 1960 // adjust the size in the major direction using the proportion
3d2085a4 1961 wxCoord majorSize = GetSizeInMajorDir(sizeThis);
ec074193
VZ
1962
1963 // if there is not enough space, don't try to distribute negative space
1964 // among the children, this would result in overlapping windows which
1965 // we don't want
1966 if ( delta > 0 )
89064717 1967 {
ec074193
VZ
1968 const int propItem = item->GetProportion();
1969 if ( propItem )
1970 {
1971 const int deltaItem = (delta * propItem) / totalProportion;
7fca7a73 1972
ec074193 1973 majorSize += deltaItem;
7fca7a73 1974
ec074193
VZ
1975 delta -= deltaItem;
1976 totalProportion -= propItem;
1977 }
89064717 1978 }
2b5f62a0 1979
2b5f62a0 1980
89064717
VZ
1981 // apply the alignment in the minor direction
1982 wxPoint posChild(pt);
2b5f62a0 1983
3d2085a4 1984 wxCoord minorSize = GetSizeInMinorDir(sizeThis);
89064717
VZ
1985 const int flag = item->GetFlag();
1986 if ( flag & (wxEXPAND | wxSHAPED) )
1987 {
1988 minorSize = totalMinorSize;
1989 }
1990 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1991 {
1992 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1993 }
1994 // NB: wxCENTRE is used here only for backwards compatibility,
1995 // wxALIGN_CENTRE should be used in new code
1a27a87d 1996 else if ( flag & (wxCENTER | (IsVertical() ? wxALIGN_CENTRE_HORIZONTAL : wxALIGN_CENTRE_VERTICAL)))
89064717
VZ
1997 {
1998 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1999 }
978af864 2000
2b5f62a0 2001
89064717
VZ
2002 // apply RTL adjustment for horizontal sizers:
2003 if ( !IsVertical() && m_containingWindow )
2004 {
2005 posChild.x = m_containingWindow->AdjustForLayoutDirection
2006 (
2007 posChild.x,
2008 majorSize,
2009 m_size.x
2010 );
3ca6a5f0
BP
2011 }
2012
89064717
VZ
2013 // finally set size of this child and advance to the next one
2014 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
2015
2016 PosInMajorDir(pt) += majorSize;
61d514bb
RR
2017 }
2018}
2019
92afa2b1 2020wxSize wxBoxSizer::CalcMin()
61d514bb 2021{
89064717
VZ
2022 m_totalProportion = 0;
2023 m_minSize = wxSize(0, 0);
0c0d686f 2024
89064717
VZ
2025 // calculate the minimal sizes for all items and count sum of proportions
2026 for ( wxSizerItemList::const_iterator i = m_children.begin();
2027 i != m_children.end();
2028 ++i )
85e5cfc9 2029 {
89064717 2030 wxSizerItem * const item = *i;
12a3f227 2031
89064717
VZ
2032 if ( !item->IsShown() )
2033 continue;
12a3f227 2034
3d2085a4
VZ
2035 const wxSize sizeMinThis = item->CalcMin();
2036 SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis);
2037 if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) )
2038 SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis);
85e5cfc9 2039
89064717 2040 m_totalProportion += item->GetProportion();
61d514bb 2041 }
0c0d686f 2042
89064717 2043 return m_minSize;
61d514bb 2044}
27ea1d8a
RR
2045
2046//---------------------------------------------------------------------------
2047// wxStaticBoxSizer
2048//---------------------------------------------------------------------------
2049
1e6feb95
VZ
2050#if wxUSE_STATBOX
2051
27ea1d8a 2052wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
e978011a
VZ
2053 : wxBoxSizer( orient ),
2054 m_staticBox( box )
27ea1d8a 2055{
223d09f6 2056 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
e978011a
VZ
2057
2058 // do this so that our Detach() is called if the static box is destroyed
2059 // before we are
2060 m_staticBox->SetContainingSizer(this);
27ea1d8a 2061}
0c0d686f 2062
6c1635b5
VZ
2063wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
2064 : wxBoxSizer(orient),
2065 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
2066{
e978011a
VZ
2067 // same as above
2068 m_staticBox->SetContainingSizer(this);
6c1635b5
VZ
2069}
2070
649cfca1
VZ
2071wxStaticBoxSizer::~wxStaticBoxSizer()
2072{
2073 delete m_staticBox;
2074}
2075
12a3f227
RL
2076static void GetStaticBoxBorders( wxStaticBox *box,
2077 int *borderTop,
2078 int *borderOther)
84028727
VZ
2079{
2080 // this has to be done platform by platform as there is no way to
2081 // guess the thickness of a wxStaticBox border
5dd070c2 2082 box->GetBordersForSizer(borderTop, borderOther);
84028727
VZ
2083}
2084
27ea1d8a
RR
2085void wxStaticBoxSizer::RecalcSizes()
2086{
84028727
VZ
2087 int top_border, other_border;
2088 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
2089
2090 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 2091
27ea1d8a
RR
2092 wxPoint old_pos( m_position );
2093 m_position.x += other_border;
2094 m_position.y += top_border;
2095 wxSize old_size( m_size );
2096 m_size.x -= 2*other_border;
2097 m_size.y -= top_border + other_border;
0c0d686f 2098
27ea1d8a 2099 wxBoxSizer::RecalcSizes();
0c0d686f 2100
27ea1d8a
RR
2101 m_position = old_pos;
2102 m_size = old_size;
2103}
2104
2105wxSize wxStaticBoxSizer::CalcMin()
2106{
84028727
VZ
2107 int top_border, other_border;
2108 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 2109
27ea1d8a 2110 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 2111 ret.x += 2*other_border;
27ea1d8a 2112 ret.y += other_border + top_border;
0c0d686f 2113
27ea1d8a
RR
2114 return ret;
2115}
83edc0a5 2116
eb2a7883
VZ
2117void wxStaticBoxSizer::ShowItems( bool show )
2118{
2119 m_staticBox->Show( show );
2120 wxBoxSizer::ShowItems( show );
2121}
2122
e978011a
VZ
2123bool wxStaticBoxSizer::Detach( wxWindow *window )
2124{
2125 // avoid deleting m_staticBox in our dtor if it's being detached from the
2126 // sizer (which can happen because it's being already destroyed for
2127 // example)
2128 if ( window == m_staticBox )
2129 {
2130 m_staticBox = NULL;
2131 return true;
2132 }
2133
2134 return wxSizer::Detach( window );
2135}
2136
1e6feb95
VZ
2137#endif // wxUSE_STATBOX
2138
974c2a59
WS
2139#if wxUSE_BUTTON
2140
acf2ac37
RR
2141wxStdDialogButtonSizer::wxStdDialogButtonSizer()
2142 : wxBoxSizer(wxHORIZONTAL)
2143{
94f53923
JS
2144 // Vertical buttons with lots of space on either side
2145 // looks rubbish on WinCE, so let's not do this for now.
2146 // If we are going to use vertical buttons, we should
2147 // put the sizer to the right of other controls in the dialog,
2148 // and that's beyond the scope of this sizer.
2149#ifndef __WXWINCE__
acf2ac37 2150 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
974c2a59 2151 // If we have a PDA screen, put yes/no button over
acf2ac37
RR
2152 // all other buttons, otherwise on the left side.
2153 if (is_pda)
2154 m_orient = wxVERTICAL;
94f53923 2155#endif
974c2a59 2156
acf2ac37
RR
2157 m_buttonAffirmative = NULL;
2158 m_buttonApply = NULL;
2159 m_buttonNegative = NULL;
2160 m_buttonCancel = NULL;
2161 m_buttonHelp = NULL;
2162}
2163
2164void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
2165{
2166 switch (mybutton->GetId())
2167 {
2168 case wxID_OK:
2169 case wxID_YES:
2170 case wxID_SAVE:
2171 m_buttonAffirmative = mybutton;
2172 break;
2173 case wxID_APPLY:
2174 m_buttonApply = mybutton;
2175 break;
2176 case wxID_NO:
2177 m_buttonNegative = mybutton;
2178 break;
2179 case wxID_CANCEL:
57d7f988 2180 case wxID_CLOSE:
acf2ac37
RR
2181 m_buttonCancel = mybutton;
2182 break;
2183 case wxID_HELP:
2997ca30 2184 case wxID_CONTEXT_HELP:
acf2ac37
RR
2185 m_buttonHelp = mybutton;
2186 break;
2187 default:
2188 break;
2189 }
2190}
2191
b181a505
RR
2192void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
2193{
2194 m_buttonAffirmative = button;
2195}
2196
2197void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
2198{
2199 m_buttonNegative = button;
2200}
2201
2202void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
2203{
2204 m_buttonCancel = button;
2205}
2206
718903fe 2207void wxStdDialogButtonSizer::Realize()
acf2ac37
RR
2208{
2209#ifdef __WXMAC__
2210 Add(0, 0, 0, wxLEFT, 6);
2211 if (m_buttonHelp)
974c2a59
WS
2212 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2213
acf2ac37
RR
2214 if (m_buttonNegative){
2215 // HIG POLICE BULLETIN - destructive buttons need extra padding
2216 // 24 pixels on either side
2217 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
2218 }
974c2a59 2219
acf2ac37 2220 // extra whitespace between help/negative and cancel/ok buttons
974c2a59
WS
2221 Add(0, 0, 1, wxEXPAND, 0);
2222
acf2ac37
RR
2223 if (m_buttonCancel){
2224 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2225 // Cancel or help should be default
2226 // m_buttonCancel->SetDefaultButton();
2227 }
974c2a59
WS
2228
2229 // Ugh, Mac doesn't really have apply dialogs, so I'll just
acf2ac37
RR
2230 // figure the best place is between Cancel and OK
2231 if (m_buttonApply)
2232 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
974c2a59 2233
acf2ac37
RR
2234 if (m_buttonAffirmative){
2235 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
974c2a59 2236
acf2ac37
RR
2237 if (m_buttonAffirmative->GetId() == wxID_SAVE){
2238 // these buttons have set labels under Mac so we should use them
2239 m_buttonAffirmative->SetLabel(_("Save"));
d9485f89
RD
2240 if (m_buttonNegative)
2241 m_buttonNegative->SetLabel(_("Don't Save"));
acf2ac37
RR
2242 }
2243 }
974c2a59 2244
acf2ac37
RR
2245 // Extra space around and at the right
2246 Add(12, 24);
2247#elif defined(__WXGTK20__)
2248 Add(0, 0, 0, wxLEFT, 9);
2249 if (m_buttonHelp)
974c2a59
WS
2250 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2251
acf2ac37 2252 // extra whitespace between help and cancel/ok buttons
974c2a59
WS
2253 Add(0, 0, 1, wxEXPAND, 0);
2254
acf2ac37
RR
2255 if (m_buttonNegative){
2256 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2257 }
974c2a59 2258
e6cfcc0d 2259 // according to HIG, in explicit apply windows the order is:
57d7f988
VZ
2260 // [ Help Apply Cancel OK ]
2261 if (m_buttonApply)
2262 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2263
acf2ac37
RR
2264 if (m_buttonCancel){
2265 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2266 // Cancel or help should be default
2267 // m_buttonCancel->SetDefaultButton();
2268 }
974c2a59 2269
acf2ac37
RR
2270 if (m_buttonAffirmative)
2271 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
0f884515
JS
2272#elif defined(__WXMSW__)
2273 // Windows
2274
2275 // right-justify buttons
2276 Add(0, 0, 1, wxEXPAND, 0);
2277
2278 if (m_buttonAffirmative){
2279 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2280 }
2281
2282 if (m_buttonNegative){
2283 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2284 }
2285
2286 if (m_buttonCancel){
2287 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2288 }
2289 if (m_buttonApply)
2290 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2291
2292 if (m_buttonHelp)
2293 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
acf2ac37 2294#else
0f884515 2295 // GTK+1 and any other platform
902725ee 2296
23b1018f 2297 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
acf2ac37 2298 if (m_buttonHelp)
974c2a59
WS
2299 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2300
acf2ac37 2301 // extra whitespace between help and cancel/ok buttons
974c2a59 2302 Add(0, 0, 1, wxEXPAND, 0);
acf2ac37
RR
2303
2304 if (m_buttonApply)
2305 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
974c2a59 2306
acf2ac37
RR
2307 if (m_buttonAffirmative){
2308 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2309 }
974c2a59 2310
acf2ac37
RR
2311 if (m_buttonNegative){
2312 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2313 }
974c2a59 2314
acf2ac37 2315 if (m_buttonCancel){
23b1018f 2316 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
acf2ac37
RR
2317 // Cancel or help should be default
2318 // m_buttonCancel->SetDefaultButton();
2319 }
974c2a59 2320
acf2ac37
RR
2321#endif
2322}
adbf2d73 2323
974c2a59 2324#endif // wxUSE_BUTTON