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