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