]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
Fix crash when using a proxy (m_protocol already gets cleaned up via CleanData())
[wxWidgets.git] / src / common / sizer.cpp
CommitLineData
5279a24d
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: 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
14f355c2 13#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
c62ac5b6 14#pragma implementation "sizer.h"
5279a24d
RR
15#endif
16
77671fd2
VZ
17// For compilers that support precompilation, includes "wx.h".
18#include "wx/wxprec.h"
19
20#ifdef __BORLANDC__
21 #pragma hdrstop
22#endif
23
0f769aab
WS
24#ifndef WX_PRECOMP
25 #include "wx/string.h"
26 #include "wx/intl.h"
27#endif // WX_PRECOMP
28
5279a24d 29#include "wx/sizer.h"
61d514bb 30#include "wx/utils.h"
27ea1d8a 31#include "wx/statbox.h"
acf2ac37 32#include "wx/settings.h"
c54b92d3 33#include "wx/listimpl.cpp"
efba61ba 34#include "wx/intl.h"
adbf2d73
VS
35#if WXWIN_COMPATIBILITY_2_4
36 #include "wx/notebook.h"
37#endif
5279a24d 38
0c0d686f
RD
39//---------------------------------------------------------------------------
40
9cbee2ce
RL
41IMPLEMENT_CLASS(wxSizerItem, wxObject)
42IMPLEMENT_CLASS(wxSizer, wxObject)
43IMPLEMENT_CLASS(wxGridSizer, wxSizer)
44IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
45IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
1e6feb95 46#if wxUSE_STATBOX
9cbee2ce 47IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
1e6feb95 48#endif
974c2a59 49#if wxUSE_BUTTON
acf2ac37 50IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
974c2a59 51#endif
0c0d686f 52
12a3f227
RL
53WX_DEFINE_EXPORTED_LIST( wxSizerItemList );
54
066f1b7a 55/*
8b2bac62
WS
56 TODO PROPERTIES
57 sizeritem
58 object
59 object_ref
60 minsize
61 option
62 flag
63 border
066f1b7a 64 spacer
8b2bac62
WS
65 option
66 flag
67 borfder
68 boxsizer
69 orient
066f1b7a 70 staticboxsizer
8b2bac62
WS
71 orient
72 label
73 gridsizer
74 rows
75 cols
76 vgap
77 hgap
78 flexgridsizer
79 rows
80 cols
81 vgap
82 hgap
83 growablerows
84 growablecols
066f1b7a
SC
85 minsize
86*/
ccbc8038 87
5279a24d 88//---------------------------------------------------------------------------
3417c2cd 89// wxSizerItem
5279a24d
RR
90//---------------------------------------------------------------------------
91
ccbc8038
VZ
92void wxSizerItem::Init()
93{
94 m_window = NULL;
95 m_sizer = NULL;
96 m_show = true;
97 m_userData = NULL;
c47addef 98 m_zoneRect = wxRect(0,0,0,0);
ccbc8038
VZ
99}
100
101void wxSizerItem::Init(const wxSizerFlags& flags)
102{
103 Init();
104
105 m_proportion = flags.GetProportion();
106 m_flag = flags.GetFlags();
107 m_border = flags.GetBorderInPixels();
108}
109
12a3f227
RL
110wxSizerItem::wxSizerItem( int width, int height, int proportion, int flag, int border, wxObject* userData )
111 : m_window( NULL )
112 , m_sizer( NULL )
00976fe5
RL
113 , m_size( wxSize( width, height ) ) // size is set directly
114 , m_minSize( m_size ) // minimal size is the initial size
12a3f227 115 , m_proportion( proportion )
00976fe5
RL
116 , m_border( border )
117 , m_flag( flag )
2997ca30 118 , m_zoneRect()
e0d8fb45 119 , m_show( true )
00976fe5 120 , m_userData( userData )
5279a24d 121{
00976fe5 122 SetRatio( m_size );
5279a24d
RR
123}
124
12a3f227 125wxSizerItem::wxSizerItem( wxWindow *window, int proportion, int flag, int border, wxObject* userData )
00976fe5 126 : m_window( window )
12a3f227 127 , m_sizer( NULL )
12a3f227 128 , m_proportion( proportion )
00976fe5
RL
129 , m_border( border )
130 , m_flag( flag )
2997ca30 131 , m_zoneRect()
e0d8fb45 132 , m_show( true )
00976fe5 133 , m_userData( userData )
5279a24d 134{
ba763a45
RD
135 if (flag & wxFIXED_MINSIZE)
136 window->SetMinSize(window->GetSize());
137 m_minSize = window->GetSize();
8b2bac62 138
36461f58
RD
139 // aspect ratio calculated from initial size
140 SetRatio( m_minSize );
141
00976fe5 142 // m_size is calculated later
5279a24d
RR
143}
144
12a3f227
RL
145wxSizerItem::wxSizerItem( wxSizer *sizer, int proportion, int flag, int border, wxObject* userData )
146 : m_window( NULL )
00976fe5 147 , m_sizer( sizer )
12a3f227 148 , m_proportion( proportion )
00976fe5
RL
149 , m_border( border )
150 , m_flag( flag )
2997ca30 151 , m_zoneRect()
e0d8fb45 152 , m_show( true )
12a3f227 153 , m_ratio( 0.0 )
00976fe5 154 , m_userData( userData )
5279a24d 155{
00976fe5
RL
156 // m_minSize is calculated later
157 // m_size is calculated later
5279a24d
RR
158}
159
20b35a69 160wxSizerItem::wxSizerItem()
20b35a69 161{
ccbc8038
VZ
162 Init();
163
164 m_proportion = 0;
165 m_border = 0;
166 m_flag = 0;
20b35a69
RD
167}
168
0c0d686f
RD
169wxSizerItem::~wxSizerItem()
170{
f91e8382
VZ
171 delete m_userData;
172
173 if ( m_window )
174 {
175 m_window->SetContainingSizer(NULL);
176 }
177 else // we must be a sizer
178 {
0c0d686f 179 delete m_sizer;
f91e8382 180 }
0c0d686f
RD
181}
182
183
9cbee2ce 184wxSize wxSizerItem::GetSize() const
5279a24d 185{
d597fcb7 186 wxSize ret;
3417c2cd 187 if (IsSizer())
d597fcb7
RR
188 ret = m_sizer->GetSize();
189 else
c62ac5b6 190 if (IsWindow())
d597fcb7
RR
191 ret = m_window->GetSize();
192 else ret = m_size;
0c0d686f 193
d597fcb7
RR
194 if (m_flag & wxWEST)
195 ret.x += m_border;
196 if (m_flag & wxEAST)
197 ret.x += m_border;
198 if (m_flag & wxNORTH)
199 ret.y += m_border;
200 if (m_flag & wxSOUTH)
201 ret.y += m_border;
0c0d686f 202
d597fcb7 203 return ret;
5279a24d
RR
204}
205
3417c2cd 206wxSize wxSizerItem::CalcMin()
c62ac5b6 207{
3417c2cd 208 if (IsSizer())
be2577e4 209 {
ba763a45 210 m_minSize = m_sizer->GetMinSize();
d13d8d4e 211
be2577e4
RD
212 // if we have to preserve aspect ratio _AND_ this is
213 // the first-time calculation, consider ret to be initial size
d13d8d4e 214 if ((m_flag & wxSHAPED) && !m_ratio)
36461f58 215 SetRatio(m_minSize);
be2577e4 216 }
ba763a45 217 else if ( IsWindow() )
d13d8d4e 218 {
ba763a45
RD
219 // Since the size of the window may change during runtime, we
220 // should use the current minimal/best size.
221 m_minSize = m_window->GetBestFittingSize();
d13d8d4e 222 }
0c0d686f 223
ba763a45
RD
224 return GetMinSizeWithBorder();
225}
226
227wxSize wxSizerItem::GetMinSizeWithBorder() const
228{
229 wxSize ret = m_minSize;
230
d597fcb7
RR
231 if (m_flag & wxWEST)
232 ret.x += m_border;
233 if (m_flag & wxEAST)
234 ret.x += m_border;
235 if (m_flag & wxNORTH)
236 ret.y += m_border;
237 if (m_flag & wxSOUTH)
238 ret.y += m_border;
8b2bac62 239
d597fcb7 240 return ret;
c62ac5b6
RR
241}
242
ba763a45 243
3417c2cd 244void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
c62ac5b6 245{
cdddaeea 246 if (m_flag & wxSHAPED)
d597fcb7 247 {
be2577e4
RD
248 // adjust aspect ratio
249 int rwidth = (int) (size.y * m_ratio);
cdddaeea
VZ
250 if (rwidth > size.x)
251 {
be2577e4
RD
252 // fit horizontally
253 int rheight = (int) (size.x / m_ratio);
254 // add vertical space
255 if (m_flag & wxALIGN_CENTER_VERTICAL)
256 pos.y += (size.y - rheight) / 2;
257 else if (m_flag & wxALIGN_BOTTOM)
258 pos.y += (size.y - rheight);
259 // use reduced dimensions
260 size.y =rheight;
cdddaeea
VZ
261 }
262 else if (rwidth < size.x)
263 {
be2577e4
RD
264 // add horizontal space
265 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
266 pos.x += (size.x - rwidth) / 2;
267 else if (m_flag & wxALIGN_RIGHT)
268 pos.x += (size.x - rwidth);
269 size.x = rwidth;
270 }
271 }
33ac7e6f 272
cdddaeea
VZ
273 // This is what GetPosition() returns. Since we calculate
274 // borders afterwards, GetPosition() will be the left/top
275 // corner of the surrounding border.
276 m_pos = pos;
277
278 if (m_flag & wxWEST)
279 {
280 pos.x += m_border;
281 size.x -= m_border;
282 }
283 if (m_flag & wxEAST)
284 {
285 size.x -= m_border;
286 }
287 if (m_flag & wxNORTH)
288 {
289 pos.y += m_border;
290 size.y -= m_border;
291 }
292 if (m_flag & wxSOUTH)
293 {
294 size.y -= m_border;
295 }
0c0d686f 296
3417c2cd 297 if (IsSizer())
c62ac5b6 298 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
0c0d686f 299
56eee37f 300 m_zoneRect = wxRect(pos, size);
c62ac5b6 301 if (IsWindow())
b919f007 302 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
d597fcb7
RR
303
304 m_size = size;
c62ac5b6
RR
305}
306
84f7908b
RR
307void wxSizerItem::DeleteWindows()
308{
309 if (m_window)
77aa9abd 310 {
84f7908b 311 m_window->Destroy();
77aa9abd
RD
312 m_window = NULL;
313 }
be90c029 314
84f7908b
RR
315 if (m_sizer)
316 m_sizer->DeleteWindows();
317}
318
9cbee2ce 319bool wxSizerItem::IsWindow() const
5279a24d
RR
320{
321 return (m_window != NULL);
322}
323
9cbee2ce 324bool wxSizerItem::IsSizer() const
5279a24d
RR
325{
326 return (m_sizer != NULL);
327}
328
9cbee2ce 329bool wxSizerItem::IsSpacer() const
5279a24d
RR
330{
331 return (m_window == NULL) && (m_sizer == NULL);
332}
333
12a3f227
RL
334void wxSizerItem::Show( bool show )
335{
336 m_show = show;
337
338 if( IsWindow() )
339 m_window->Show( show );
340 else if( IsSizer() )
341 m_sizer->ShowItems( show );
342
343 // ... nothing else to do to hide/show spacers
344}
345
346void wxSizerItem::SetOption( int option )
347{
348 SetProportion( option );
349}
350
351int wxSizerItem::GetOption() const
352{
353 return GetProportion();
354}
355
356
5279a24d 357//---------------------------------------------------------------------------
3417c2cd 358// wxSizer
5279a24d
RR
359//---------------------------------------------------------------------------
360
3417c2cd 361wxSizer::wxSizer()
2997ca30 362 :m_minSize()
5279a24d 363{
5279a24d
RR
364}
365
3417c2cd 366wxSizer::~wxSizer()
5279a24d 367{
222ed1d6 368 WX_CLEAR_LIST(wxSizerItemList, m_children);
5279a24d 369}
0c0d686f 370
56eee37f 371wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
12a3f227
RL
372{
373 m_children.Insert( index, item );
0c0d686f 374
12a3f227
RL
375 if( item->GetWindow() )
376 item->GetWindow()->SetContainingSizer( this );
56eee37f
WS
377
378 return item;
12a3f227
RL
379}
380
381bool wxSizer::Remove( wxWindow *window )
382{
383 return Detach( window );
42b4e99e
RR
384}
385
386bool wxSizer::Remove( wxSizer *sizer )
387{
12a3f227 388 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
0c0d686f 389
222ed1d6 390 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
42b4e99e
RR
391 while (node)
392 {
12a3f227
RL
393 wxSizerItem *item = node->GetData();
394
3ca6a5f0 395 if (item->GetSizer() == sizer)
222ed1d6
MB
396 {
397 delete item;
398 m_children.Erase( node );
399 return true;
400 }
12a3f227
RL
401
402 node = node->GetNext();
42b4e99e 403 }
0c0d686f 404
e0d8fb45 405 return false;
42b4e99e
RR
406}
407
e0d8fb45 408bool wxSizer::Remove( int index )
42b4e99e 409{
e0d8fb45
VZ
410 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
411 false,
12a3f227 412 _T("Remove index is out of range") );
0c0d686f 413
222ed1d6 414 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
0c0d686f 415
e0d8fb45 416 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227 417
e0d8fb45 418 wxSizerItem *item = node->GetData();
9cbee2ce
RL
419
420 if( item->IsWindow() )
421 item->GetWindow()->SetContainingSizer( NULL );
422
222ed1d6
MB
423 delete item;
424 m_children.Erase( node );
425 return true;
42b4e99e 426}
0c0d686f 427
00976fe5
RL
428bool wxSizer::Detach( wxSizer *sizer )
429{
12a3f227 430 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
00976fe5 431
222ed1d6 432 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
00976fe5
RL
433 while (node)
434 {
12a3f227
RL
435 wxSizerItem *item = node->GetData();
436
00976fe5
RL
437 if (item->GetSizer() == sizer)
438 {
96fdbb60 439 item->DetachSizer();
89c20ac1 440 delete item;
222ed1d6
MB
441 m_children.Erase( node );
442 return true;
12a3f227
RL
443 }
444 node = node->GetNext();
445 }
446
e0d8fb45 447 return false;
12a3f227
RL
448}
449
450bool wxSizer::Detach( wxWindow *window )
451{
452 wxASSERT_MSG( window, _T("Detaching NULL window") );
453
222ed1d6 454 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
455 while (node)
456 {
457 wxSizerItem *item = node->GetData();
458
459 if (item->GetWindow() == window)
460 {
461 item->GetWindow()->SetContainingSizer( NULL );
89c20ac1 462 delete item;
222ed1d6
MB
463 m_children.Erase( node );
464 return true;
00976fe5 465 }
12a3f227 466 node = node->GetNext();
00976fe5
RL
467 }
468
e0d8fb45 469 return false;
00976fe5
RL
470}
471
e0d8fb45 472bool wxSizer::Detach( int index )
00976fe5 473{
e0d8fb45
VZ
474 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
475 false,
12a3f227
RL
476 _T("Detach index is out of range") );
477
222ed1d6 478 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
00976fe5 479
e0d8fb45 480 wxCHECK_MSG( node, false, _T("Failed to find child node") );
00976fe5 481
e0d8fb45 482 wxSizerItem *item = node->GetData();
9cbee2ce
RL
483
484 if( item->IsSizer() )
485 item->DetachSizer();
486 else if( item->IsWindow() )
487 item->GetWindow()->SetContainingSizer( NULL );
12a3f227 488
89c20ac1 489 delete item;
222ed1d6
MB
490 m_children.Erase( node );
491 return true;
00976fe5
RL
492}
493
84f7908b
RR
494void wxSizer::Clear( bool delete_windows )
495{
be90c029 496 // First clear the ContainingSizer pointers
222ed1d6 497 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
be90c029
RD
498 while (node)
499 {
12a3f227
RL
500 wxSizerItem *item = node->GetData();
501
be90c029 502 if (item->IsWindow())
12a3f227
RL
503 item->GetWindow()->SetContainingSizer( NULL );
504 node = node->GetNext();
be90c029
RD
505 }
506
507 // Destroy the windows if needed
84f7908b
RR
508 if (delete_windows)
509 DeleteWindows();
be90c029
RD
510
511 // Now empty the list
222ed1d6 512 WX_CLEAR_LIST(wxSizerItemList, m_children);
84f7908b
RR
513}
514
515void wxSizer::DeleteWindows()
516{
222ed1d6 517 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
84f7908b
RR
518 while (node)
519 {
12a3f227
RL
520 wxSizerItem *item = node->GetData();
521
84f7908b 522 item->DeleteWindows();
12a3f227 523 node = node->GetNext();
84f7908b
RR
524 }
525}
526
e5251d4f 527wxSize wxSizer::Fit( wxWindow *window )
5279a24d 528{
f43c7771
VZ
529 wxSize size(window->IsTopLevel() ? FitSize(window)
530 : GetMinWindowSize(window));
9ef2e675 531
ccf5c8a8 532 window->SetSize( size );
e5251d4f
VZ
533
534 return size;
5279a24d
RR
535}
536
566d84a7
RL
537void wxSizer::FitInside( wxWindow *window )
538{
539 wxSize size;
540 if (window->IsTopLevel())
541 size = VirtualFitSize( window );
542 else
543 size = GetMinClientSize( window );
544
545 window->SetVirtualSize( size );
546}
547
3417c2cd 548void wxSizer::Layout()
c62ac5b6 549{
ba763a45
RD
550 // (re)calculates minimums needed for each item and other preparations
551 // for layout
42b4e99e 552 CalcMin();
ba763a45
RD
553
554 // Applies the layout and repositions/resizes the items
c62ac5b6
RR
555 RecalcSizes();
556}
557
3417c2cd 558void wxSizer::SetSizeHints( wxWindow *window )
5279a24d 559{
34c3ffca
RL
560 // Preserve the window's max size hints, but set the
561 // lower bound according to the sizer calculations.
562
e5251d4f
VZ
563 wxSize size = Fit( window );
564
34c3ffca
RL
565 window->SetSizeHints( size.x,
566 size.y,
567 window->GetMaxWidth(),
568 window->GetMaxHeight() );
5279a24d
RR
569}
570
566d84a7
RL
571void wxSizer::SetVirtualSizeHints( wxWindow *window )
572{
573 // Preserve the window's max size hints, but set the
574 // lower bound according to the sizer calculations.
575
576 FitInside( window );
577 wxSize size( window->GetVirtualSize() );
578 window->SetVirtualSizeHints( size.x,
579 size.y,
580 window->GetMaxWidth(),
581 window->GetMaxHeight() );
582}
583
9cbee2ce 584wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
65ba4113 585{
34c3ffca 586 return window->GetMaxSize();
65ba4113
GT
587}
588
3417c2cd 589wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 590{
12a3f227
RL
591 wxSize minSize( GetMinSize() );
592 wxSize size( window->GetSize() );
593 wxSize client_size( window->GetClientSize() );
594
77671fd2 595 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 596 minSize.y+size.y-client_size.y );
5279a24d
RR
597}
598
e11d436b
SC
599// TODO on mac we need a function that determines how much free space this
600// min size contains, in order to make sure that we have 20 pixels of free
601// space around the controls
602
65ba4113
GT
603// Return a window size that will fit within the screens dimensions
604wxSize wxSizer::FitSize( wxWindow *window )
605{
606 wxSize size = GetMinWindowSize( window );
607 wxSize sizeMax = GetMaxWindowSize( window );
608
34c3ffca
RL
609 // Limit the size if sizeMax != wxDefaultSize
610
d775fa82 611 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
65ba4113 612 size.x = sizeMax.x;
d775fa82 613 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
65ba4113
GT
614 size.y = sizeMax.y;
615
616 return size;
617}
618
9cbee2ce 619wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
566d84a7
RL
620{
621 wxSize maxSize( window->GetMaxSize() );
622
623 if( maxSize != wxDefaultSize )
624 {
625 wxSize size( window->GetSize() );
626 wxSize client_size( window->GetClientSize() );
627
628 return wxSize( maxSize.x + client_size.x - size.x,
629 maxSize.y + client_size.y - size.y );
630 }
631 else
632 return wxDefaultSize;
633}
634
1b0674f7 635wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
566d84a7
RL
636{
637 return GetMinSize(); // Already returns client size.
638}
639
640wxSize wxSizer::VirtualFitSize( wxWindow *window )
641{
642 wxSize size = GetMinClientSize( window );
643 wxSize sizeMax = GetMaxClientSize( window );
644
645 // Limit the size if sizeMax != wxDefaultSize
646
d775fa82 647 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
566d84a7 648 size.x = sizeMax.x;
d775fa82 649 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
566d84a7
RL
650 size.y = sizeMax.y;
651
652 return size;
653}
654
3417c2cd 655void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
656{
657 m_position.x = x;
658 m_position.y = y;
659 m_size.x = width;
660 m_size.y = height;
2b5f62a0 661 Layout();
5279a24d
RR
662}
663
f6bcfd97 664wxSize wxSizer::GetMinSize()
3ca6a5f0 665{
f6bcfd97
BP
666 wxSize ret( CalcMin() );
667 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
668 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
3ca6a5f0 669 return ret;
f6bcfd97
BP
670}
671
672void wxSizer::DoSetMinSize( int width, int height )
673{
674 m_minSize.x = width;
675 m_minSize.y = height;
676}
677
678bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
679{
12a3f227
RL
680 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
681
682 // Is it our immediate child?
f6bcfd97 683
222ed1d6 684 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
685 while (node)
686 {
12a3f227
RL
687 wxSizerItem *item = node->GetData();
688
3ca6a5f0
BP
689 if (item->GetWindow() == window)
690 {
1eba2193 691 item->SetMinSize( width, height );
e0d8fb45 692 return true;
3ca6a5f0 693 }
12a3f227 694 node = node->GetNext();
f6bcfd97
BP
695 }
696
12a3f227
RL
697 // No? Search any subsizers we own then
698
699 node = m_children.GetFirst();
f6bcfd97
BP
700 while (node)
701 {
12a3f227
RL
702 wxSizerItem *item = node->GetData();
703
704 if ( item->GetSizer() &&
705 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
3ca6a5f0 706 {
12a3f227 707 // A child sizer found the requested windw, exit.
e0d8fb45 708 return true;
3ca6a5f0 709 }
12a3f227 710 node = node->GetNext();
f6bcfd97
BP
711 }
712
e0d8fb45 713 return false;
f6bcfd97
BP
714}
715
716bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
717{
12a3f227 718 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
f6bcfd97 719
12a3f227
RL
720 // Is it our immediate child?
721
222ed1d6 722 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
723 while (node)
724 {
12a3f227
RL
725 wxSizerItem *item = node->GetData();
726
3ca6a5f0
BP
727 if (item->GetSizer() == sizer)
728 {
f6bcfd97 729 item->GetSizer()->DoSetMinSize( width, height );
e0d8fb45 730 return true;
3ca6a5f0 731 }
12a3f227 732 node = node->GetNext();
f6bcfd97
BP
733 }
734
12a3f227
RL
735 // No? Search any subsizers we own then
736
737 node = m_children.GetFirst();
f6bcfd97
BP
738 while (node)
739 {
12a3f227
RL
740 wxSizerItem *item = node->GetData();
741
742 if ( item->GetSizer() &&
743 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
3ca6a5f0 744 {
12a3f227 745 // A child found the requested sizer, exit.
e0d8fb45 746 return true;
3ca6a5f0 747 }
12a3f227 748 node = node->GetNext();
f6bcfd97
BP
749 }
750
e0d8fb45 751 return false;
f6bcfd97
BP
752}
753
12a3f227 754bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
f6bcfd97 755{
222ed1d6 756 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
12a3f227 757
e0d8fb45 758 wxCHECK_MSG( node, false, _T("Failed to find child node") );
12a3f227
RL
759
760 wxSizerItem *item = node->GetData();
f6bcfd97 761
f6bcfd97
BP
762 if (item->GetSizer())
763 {
0ca5105b 764 // Sizers contains the minimal size in them, if not calculated ...
f6bcfd97
BP
765 item->GetSizer()->DoSetMinSize( width, height );
766 }
767 else
768 {
ba763a45 769 // ... but the minimal size of spacers and windows is stored via the item
1eba2193 770 item->SetMinSize( width, height );
f6bcfd97
BP
771 }
772
e0d8fb45 773 return true;
f6bcfd97
BP
774}
775
9f13661f 776wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
2b5f62a0 777{
9f13661f 778 wxASSERT_MSG( window, _T("GetItem for NULL window") );
12a3f227 779
222ed1d6 780 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
781 while (node)
782 {
12a3f227 783 wxSizerItem *item = node->GetData();
2b5f62a0 784
12a3f227 785 if (item->GetWindow() == window)
2b5f62a0 786 {
9f13661f 787 return item;
2b5f62a0 788 }
8b2bac62
WS
789 else if (recursive && item->IsSizer())
790 {
9f13661f
WS
791 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
792 if (subitem)
793 return subitem;
8b2bac62
WS
794 }
795
12a3f227 796 node = node->GetNext();
2b5f62a0 797 }
8b2bac62 798
9f13661f 799 return NULL;
2b5f62a0
VZ
800}
801
9f13661f 802wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
2b5f62a0 803{
9f13661f 804 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
12a3f227 805
222ed1d6 806 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
807 while (node)
808 {
9f13661f 809 wxSizerItem *item = node->GetData();
2b5f62a0 810
12a3f227 811 if (item->GetSizer() == sizer)
2b5f62a0 812 {
9f13661f 813 return item;
2b5f62a0 814 }
8b2bac62
WS
815 else if (recursive && item->IsSizer())
816 {
9f13661f
WS
817 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
818 if (subitem)
819 return subitem;
8b2bac62
WS
820 }
821
12a3f227 822 node = node->GetNext();
2b5f62a0 823 }
8b2bac62 824
9f13661f
WS
825 return NULL;
826}
827
828wxSizerItem* wxSizer::GetItem( size_t index )
829{
830 wxCHECK_MSG( index < m_children.GetCount(),
831 NULL,
832 _T("GetItem index is out of range") );
833
834 return m_children.Item( index )->GetData();
835}
836
837bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
838{
839 wxSizerItem *item = GetItem( window, recursive );
840
841 if ( item )
842 {
843 item->Show( show );
844 return true;
845 }
846
847 return false;
848}
849
850bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
851{
852 wxSizerItem *item = GetItem( sizer, recursive );
853
854 if ( item )
855 {
856 item->Show( show );
857 return true;
858 }
859
8b2bac62 860 return false;
2b5f62a0
VZ
861}
862
8b2bac62 863bool wxSizer::Show( size_t index, bool show)
2b5f62a0 864{
9f13661f 865 wxSizerItem *item = GetItem( index );
2b5f62a0 866
9f13661f
WS
867 if ( item )
868 {
869 item->Show( show );
870 return true;
871 }
8b2bac62 872
9f13661f 873 return false;
12a3f227 874}
2b5f62a0 875
12a3f227
RL
876void wxSizer::ShowItems( bool show )
877{
222ed1d6 878 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227
RL
879 while (node)
880 {
881 node->GetData()->Show( show );
882 node = node->GetNext();
2b5f62a0
VZ
883 }
884}
885
9cbee2ce 886bool wxSizer::IsShown( wxWindow *window ) const
2b5f62a0 887{
222ed1d6 888 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
889 while (node)
890 {
12a3f227 891 wxSizerItem *item = node->GetData();
dc259b79 892
12a3f227 893 if (item->GetWindow() == window)
2b5f62a0
VZ
894 {
895 return item->IsShown();
896 }
12a3f227 897 node = node->GetNext();
2b5f62a0
VZ
898 }
899
12a3f227
RL
900 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
901
e0d8fb45 902 return false;
2b5f62a0
VZ
903}
904
9cbee2ce 905bool wxSizer::IsShown( wxSizer *sizer ) const
2b5f62a0 906{
222ed1d6 907 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2b5f62a0
VZ
908 while (node)
909 {
12a3f227 910 wxSizerItem *item = node->GetData();
2b5f62a0 911
12a3f227 912 if (item->GetSizer() == sizer)
2b5f62a0
VZ
913 {
914 return item->IsShown();
915 }
12a3f227 916 node = node->GetNext();
2b5f62a0
VZ
917 }
918
12a3f227
RL
919 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
920
e0d8fb45 921 return false;
2b5f62a0
VZ
922}
923
9cbee2ce 924bool wxSizer::IsShown( size_t index ) const
12a3f227
RL
925{
926 wxCHECK_MSG( index < m_children.GetCount(),
e0d8fb45 927 false,
12a3f227
RL
928 _T("IsShown index is out of range") );
929
930 return m_children.Item( index )->GetData()->IsShown();
931}
932
933
f6bcfd97
BP
934//---------------------------------------------------------------------------
935// wxGridSizer
936//---------------------------------------------------------------------------
937
938wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
12a3f227
RL
939 : m_rows( rows )
940 , m_cols( cols )
941 , m_vgap( vgap )
942 , m_hgap( hgap )
f6bcfd97 943{
02319c24
RD
944 if (m_rows == 0 && m_cols == 0)
945 m_rows = 1;
f6bcfd97
BP
946}
947
948wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
12a3f227
RL
949 : m_rows( 0 )
950 , m_cols( cols )
951 , m_vgap( vgap )
952 , m_hgap( hgap )
f6bcfd97 953{
02319c24
RD
954 if (m_rows == 0 && m_cols == 0)
955 m_rows = 1;
f6bcfd97
BP
956}
957
0ca5105b 958int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
f6bcfd97 959{
f6bcfd97 960 int nitems = m_children.GetCount();
2b5f62a0 961 if ( nitems)
0ca5105b
VZ
962 {
963 if ( m_cols )
964 {
965 ncols = m_cols;
966 nrows = (nitems + m_cols - 1) / m_cols;
967 }
968 else if ( m_rows )
969 {
970 ncols = (nitems + m_rows - 1) / m_rows;
971 nrows = m_rows;
972 }
973 else // 0 columns, 0 rows?
974 {
975 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
f6bcfd97 976
0ca5105b
VZ
977 nrows = ncols = 0;
978 }
979 }
980
981 return nitems;
982}
983
984void wxGridSizer::RecalcSizes()
985{
986 int nitems, nrows, ncols;
987 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
988 return;
f6bcfd97
BP
989
990 wxSize sz( GetSize() );
991 wxPoint pt( GetPosition() );
3ca6a5f0
BP
992
993 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
994 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
f6bcfd97
BP
995
996 int x = pt.x;
997 for (int c = 0; c < ncols; c++)
998 {
999 int y = pt.y;
1000 for (int r = 0; r < nrows; r++)
1001 {
1002 int i = r * ncols + c;
1003 if (i < nitems)
1004 {
222ed1d6 1005 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1006
1007 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
3ca6a5f0 1008
12a3f227 1009 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97
BP
1010 }
1011 y = y + h + m_vgap;
1012 }
1013 x = x + w + m_hgap;
1014 }
1015}
1016
1017wxSize wxGridSizer::CalcMin()
1018{
196be0f1
JS
1019 int nrows, ncols;
1020 if ( CalcRowsCols(nrows, ncols) == 0 )
0ca5105b 1021 return wxSize(10, 10);
f6bcfd97 1022
4f469fb5 1023 // Find the max width and height for any component
f6bcfd97
BP
1024 int w = 0;
1025 int h = 0;
3ca6a5f0 1026
222ed1d6 1027 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
f6bcfd97
BP
1028 while (node)
1029 {
12a3f227
RL
1030 wxSizerItem *item = node->GetData();
1031 wxSize sz( item->CalcMin() );
1032
f6bcfd97
BP
1033 w = wxMax( w, sz.x );
1034 h = wxMax( h, sz.y );
3ca6a5f0 1035
12a3f227 1036 node = node->GetNext();
f6bcfd97 1037 }
3ca6a5f0 1038
12a3f227
RL
1039 return wxSize( ncols * w + (ncols-1) * m_hgap,
1040 nrows * h + (nrows-1) * m_vgap );
f6bcfd97
BP
1041}
1042
1043void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1044{
1045 wxPoint pt( x,y );
8b2bac62 1046 wxSize sz( item->GetMinSizeWithBorder() );
f6bcfd97
BP
1047 int flag = item->GetFlag();
1048
1049 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1050 {
1051 sz = wxSize(w, h);
1052 }
1053 else
1054 {
1055 if (flag & wxALIGN_CENTER_HORIZONTAL)
1056 {
559b747d 1057 pt.x = x + (w - sz.x) / 2;
f6bcfd97
BP
1058 }
1059 else if (flag & wxALIGN_RIGHT)
1060 {
559b747d 1061 pt.x = x + (w - sz.x);
f6bcfd97 1062 }
3ca6a5f0 1063
f6bcfd97
BP
1064 if (flag & wxALIGN_CENTER_VERTICAL)
1065 {
559b747d 1066 pt.y = y + (h - sz.y) / 2;
f6bcfd97
BP
1067 }
1068 else if (flag & wxALIGN_BOTTOM)
1069 {
559b747d 1070 pt.y = y + (h - sz.y);
f6bcfd97
BP
1071 }
1072 }
3ca6a5f0 1073
f6bcfd97
BP
1074 item->SetDimension(pt, sz);
1075}
1076
1077//---------------------------------------------------------------------------
1078// wxFlexGridSizer
1079//---------------------------------------------------------------------------
1080
1081wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
5d76f462
VZ
1082 : wxGridSizer( rows, cols, vgap, hgap ),
1083 m_flexDirection(wxBOTH),
1084 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1085{
f6bcfd97
BP
1086}
1087
1088wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
5d76f462
VZ
1089 : wxGridSizer( cols, vgap, hgap ),
1090 m_flexDirection(wxBOTH),
1091 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
3ca6a5f0 1092{
f6bcfd97 1093}
3ca6a5f0 1094
f6bcfd97
BP
1095wxFlexGridSizer::~wxFlexGridSizer()
1096{
f6bcfd97
BP
1097}
1098
1099void wxFlexGridSizer::RecalcSizes()
1100{
0ca5105b
VZ
1101 int nitems, nrows, ncols;
1102 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
f6bcfd97
BP
1103 return;
1104
20b35a69 1105 wxPoint pt( GetPosition() );
f6bcfd97 1106 wxSize sz( GetSize() );
5d76f462 1107
ba763a45 1108 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
3ca6a5f0 1109
f6bcfd97
BP
1110 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1111
1112 int x = pt.x;
1113 for (int c = 0; c < ncols; c++)
1114 {
1115 int y = pt.y;
1116 for (int r = 0; r < nrows; r++)
1117 {
1118 int i = r * ncols + c;
1119 if (i < nitems)
1120 {
222ed1d6 1121 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
12a3f227
RL
1122
1123 wxASSERT_MSG( node, _T("Failed to find node") );
3ca6a5f0 1124
f6bcfd97
BP
1125 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1126 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
3ca6a5f0 1127
12a3f227 1128 SetItemBounds( node->GetData(), x, y, w, h);
f6bcfd97 1129 }
53701799
RD
1130 if (m_rowHeights[r] != -1)
1131 y = y + m_rowHeights[r] + m_vgap;
f6bcfd97 1132 }
53701799
RD
1133 if (m_colWidths[c] != -1)
1134 x = x + m_colWidths[c] + m_hgap;
f6bcfd97
BP
1135 }
1136}
1137
1138wxSize wxFlexGridSizer::CalcMin()
1139{
150c8d89
RL
1140 int nrows,
1141 ncols;
1142 size_t i, s;
1143
55f9f0cb 1144 // Number of rows/columns can change as items are added or removed.
5d76f462
VZ
1145 if ( !CalcRowsCols(nrows, ncols) )
1146 return wxSize(10, 10);
f6bcfd97 1147
5d76f462
VZ
1148 m_rowHeights.SetCount(nrows);
1149 m_colWidths.SetCount(ncols);
3ca6a5f0 1150
395a82b1
VZ
1151 // We have to recalcuate the sizes in case the item minimum size has
1152 // changed since the previous layout, or the item has been hidden using
1153 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1154 // dimension of the row/column will be -1, indicating that the column
1155 // itself is hidden.
55f9f0cb
VZ
1156 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1157 m_rowHeights[ i ] = -1;
1158 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1159 m_colWidths[ i ] = -1;
1160
222ed1d6 1161 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
12a3f227 1162
150c8d89 1163 i = 0;
f6bcfd97
BP
1164 while (node)
1165 {
12a3f227 1166 wxSizerItem *item = node->GetData();
55f9f0cb
VZ
1167 if ( item->IsShown() )
1168 {
1169 wxSize sz( item->CalcMin() );
1170 int row = i / ncols;
1171 int col = i % ncols;
12a3f227 1172
55f9f0cb
VZ
1173 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1174 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1175 }
3ca6a5f0 1176
12a3f227 1177 node = node->GetNext();
f6bcfd97
BP
1178 i++;
1179 }
3ca6a5f0 1180
20b35a69 1181 AdjustForFlexDirection();
8b2bac62 1182
20b35a69
RD
1183 // Sum total minimum size, including gaps between rows/columns.
1184 // -1 is used as a magic number meaning empty column.
1185 int width = 0;
1186 for (int col = 0; col < ncols; col++)
1187 if ( m_colWidths[ col ] != -1 )
53701799
RD
1188 width += m_colWidths[ col ] + m_hgap;
1189 if (width > 0)
1190 width -= m_hgap;
20b35a69
RD
1191
1192 int height = 0;
1193 for (int row = 0; row < nrows; row++)
1194 if ( m_rowHeights[ row ] != -1 )
53701799
RD
1195 height += m_rowHeights[ row ] + m_vgap;
1196 if (height > 0)
1197 height -= m_vgap;
20b35a69 1198
ba763a45
RD
1199 m_calculatedMinSize = wxSize( width, height );
1200 return m_calculatedMinSize;
20b35a69
RD
1201}
1202
1203void wxFlexGridSizer::AdjustForFlexDirection()
1204{
1205 // the logic in CalcMin works when we resize flexibly in both directions
1206 // but maybe this is not the case
5d76f462
VZ
1207 if ( m_flexDirection != wxBOTH )
1208 {
1209 // select the array corresponding to the direction in which we do *not*
1210 // resize flexibly
1211 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1212 : m_rowHeights;
1213
1214 const int count = array.GetCount();
1215
1216 // find the largest value in this array
55f9f0cb 1217 int n, largest = 0;
5d76f462
VZ
1218 for ( n = 0; n < count; ++n )
1219 {
1220 if ( array[n] > largest )
1221 largest = array[n];
1222 }
1223
1224 // and now fill it with the largest value
1225 for ( n = 0; n < count; ++n )
1226 {
1227 array[n] = largest;
1228 }
1229 }
8b2bac62 1230}
5d76f462 1231
3ca6a5f0 1232
20b35a69
RD
1233void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1234 int nrows, int ncols)
1235{
1236 // what to do with the rows? by default, resize them proportionally
1237 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1238 {
1239 int sum_proportions = 0;
1240 int growable_space = 0;
1241 int num = 0;
1242 size_t idx;
1243 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1244 {
1245 // Since the number of rows/columns can change as items are
1246 // inserted/deleted, we need to verify at runtime that the
1247 // requested growable rows/columns are still valid.
1248 if (m_growableRows[idx] >= nrows)
1249 continue;
8b2bac62 1250
20b35a69
RD
1251 // If all items in a row/column are hidden, that row/column will
1252 // have a dimension of -1. This causes the row/column to be
1253 // hidden completely.
1254 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1255 continue;
1256 sum_proportions += m_growableRowsProportions[idx];
1257 growable_space += m_rowHeights[ m_growableRows[idx] ];
1258 num++;
1259 }
3ca6a5f0 1260
20b35a69
RD
1261 if (num > 0)
1262 {
1263 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1264 {
1265 if (m_growableRows[idx] >= nrows )
1266 continue;
1267 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1268 m_rowHeights[ m_growableRows[idx] ] = 0;
1269 else
1270 {
1271 int delta = (sz.y - minsz.y);
1272 if (sum_proportions == 0)
1273 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1274 else
1275 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1276 m_rowHeights[ m_growableRows[idx] ] = delta;
1277 }
1278 }
1279 }
1280 }
1281 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1282 {
1283 // rounding problem?
1284 for ( int row = 0; row < nrows; ++row )
1285 m_rowHeights[ row ] = sz.y / nrows;
1286 }
1287
1288 // the same logic as above but for the columns
1289 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1290 {
1291 int sum_proportions = 0;
1292 int growable_space = 0;
1293 int num = 0;
1294 size_t idx;
1295 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1296 {
1297 // Since the number of rows/columns can change as items are
1298 // inserted/deleted, we need to verify at runtime that the
1299 // requested growable rows/columns are still valid.
1300 if (m_growableCols[idx] >= ncols)
1301 continue;
8b2bac62 1302
20b35a69
RD
1303 // If all items in a row/column are hidden, that row/column will
1304 // have a dimension of -1. This causes the column to be hidden
1305 // completely.
1306 if (m_colWidths[ m_growableCols[idx] ] == -1)
1307 continue;
1308 sum_proportions += m_growableColsProportions[idx];
1309 growable_space += m_colWidths[ m_growableCols[idx] ];
1310 num++;
1311 }
1312
1313 if (num > 0)
1314 {
1315 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1316 {
1317 if (m_growableCols[idx] >= ncols )
1318 continue;
1319 if (m_colWidths[ m_growableCols[idx] ] == -1)
1320 m_colWidths[ m_growableCols[idx] ] = 0;
1321 else
1322 {
1323 int delta = (sz.x - minsz.x);
1324 if (sum_proportions == 0)
1325 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1326 else
1327 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1328 m_colWidths[ m_growableCols[idx] ] = delta;
1329 }
1330 }
1331 }
1332 }
1333 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1334 {
1335 for ( int col=0; col < ncols; ++col )
1336 m_colWidths[ col ] = sz.x / ncols;
1337 }
f6bcfd97
BP
1338}
1339
20b35a69 1340
e8800dcf 1341void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
f6bcfd97
BP
1342{
1343 m_growableRows.Add( idx );
e8800dcf 1344 m_growableRowsProportions.Add( proportion );
f6bcfd97
BP
1345}
1346
8d2474f4 1347void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
f6bcfd97 1348{
8d2474f4 1349 m_growableRows.Remove( idx );
f6bcfd97
BP
1350}
1351
e8800dcf 1352void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
f6bcfd97
BP
1353{
1354 m_growableCols.Add( idx );
e8800dcf 1355 m_growableColsProportions.Add( proportion );
f6bcfd97
BP
1356}
1357
8d2474f4 1358void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
f6bcfd97 1359{
8d2474f4 1360 m_growableCols.Remove( idx );
f6bcfd97
BP
1361}
1362
c62ac5b6 1363//---------------------------------------------------------------------------
92afa2b1 1364// wxBoxSizer
61d514bb
RR
1365//---------------------------------------------------------------------------
1366
92afa2b1 1367wxBoxSizer::wxBoxSizer( int orient )
12a3f227 1368 : m_orient( orient )
61d514bb 1369{
61d514bb
RR
1370}
1371
92afa2b1 1372void wxBoxSizer::RecalcSizes()
61d514bb
RR
1373{
1374 if (m_children.GetCount() == 0)
61d514bb 1375 return;
0c0d686f 1376
61d514bb 1377 int delta = 0;
61d514bb
RR
1378 if (m_stretchable)
1379 {
1380 if (m_orient == wxHORIZONTAL)
85e5cfc9 1381 delta = m_size.x - m_fixedWidth;
3ca6a5f0 1382 else
85e5cfc9 1383 delta = m_size.y - m_fixedHeight;
61d514bb 1384 }
0c0d686f 1385
61d514bb 1386 wxPoint pt( m_position );
0c0d686f 1387
222ed1d6 1388 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
61d514bb
RR
1389 while (node)
1390 {
12a3f227
RL
1391 wxSizerItem *item = node->GetData();
1392
2b5f62a0 1393 if (item->IsShown())
3ca6a5f0 1394 {
ba763a45 1395 wxSize size( item->GetMinSizeWithBorder() );
3ca6a5f0 1396
2b5f62a0 1397 if (m_orient == wxVERTICAL)
3ca6a5f0 1398 {
2b5f62a0 1399 wxCoord height = size.y;
12a3f227 1400 if (item->GetProportion())
2b5f62a0 1401 {
85e5cfc9
VZ
1402 // Because of at least one visible item has non-zero
1403 // proportion then m_stretchable is not zero
1404 height = (delta * item->GetProportion()) / m_stretchable;
2b5f62a0
VZ
1405 }
1406
1407 wxPoint child_pos( pt );
42841dfc 1408 wxSize child_size( size.x, height );
2b5f62a0
VZ
1409
1410 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1411 child_size.x = m_size.x;
1412 else if (item->GetFlag() & wxALIGN_RIGHT)
1413 child_pos.x += m_size.x - size.x;
1414 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1415 // XXX wxCENTER is added for backward compatibility;
1416 // wxALIGN_CENTER should be used in new code
1417 child_pos.x += (m_size.x - size.x) / 2;
1418
1419 item->SetDimension( child_pos, child_size );
1420
1421 pt.y += height;
1422 }
1423 else
1424 {
1425 wxCoord width = size.x;
12a3f227 1426 if (item->GetProportion())
2b5f62a0 1427 {
85e5cfc9
VZ
1428 // Because of at least one visible item has non-zero
1429 // proportion then m_stretchable is not zero
1430 width = (delta * item->GetProportion()) / m_stretchable;
2b5f62a0
VZ
1431 }
1432
1433 wxPoint child_pos( pt );
42841dfc 1434 wxSize child_size( width, size.y );
2b5f62a0
VZ
1435
1436 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1437 child_size.y = m_size.y;
1438 else if (item->GetFlag() & wxALIGN_BOTTOM)
1439 child_pos.y += m_size.y - size.y;
1440 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1441 // XXX wxCENTER is added for backward compatibility;
1442 // wxALIGN_CENTER should be used in new code
1443 child_pos.y += (m_size.y - size.y) / 2;
1444
1445 item->SetDimension( child_pos, child_size );
1446
1447 pt.x += width;
3ca6a5f0 1448 }
3ca6a5f0
BP
1449 }
1450
12a3f227 1451 node = node->GetNext();
61d514bb
RR
1452 }
1453}
1454
92afa2b1 1455wxSize wxBoxSizer::CalcMin()
61d514bb
RR
1456{
1457 if (m_children.GetCount() == 0)
c7a9fa36 1458 return wxSize(10,10);
0c0d686f 1459
61d514bb
RR
1460 m_stretchable = 0;
1461 m_minWidth = 0;
1462 m_minHeight = 0;
1463 m_fixedWidth = 0;
1464 m_fixedHeight = 0;
0c0d686f 1465
ba763a45 1466 // precalc item minsizes and count proportions
222ed1d6 1467 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
85e5cfc9
VZ
1468 while (node)
1469 {
1470 wxSizerItem *item = node->GetData();
12a3f227 1471
ba763a45
RD
1472 if (item->IsShown())
1473 item->CalcMin(); // result is stored in the item
8b2bac62 1474
85e5cfc9
VZ
1475 if (item->IsShown() && item->GetProportion() != 0)
1476 m_stretchable += item->GetProportion();
1477
1478 node = node->GetNext();
1479 }
1480
1481 // Total minimum size (width or height) of sizer
1482 int maxMinSize = 0;
1483
1484 node = m_children.GetFirst();
61d514bb 1485 while (node)
f98de448 1486 {
85e5cfc9 1487 wxSizerItem *item = node->GetData();
12a3f227
RL
1488
1489 if (item->IsShown() && item->GetProportion() != 0)
f98de448 1490 {
12a3f227 1491 int stretch = item->GetProportion();
ba763a45 1492 wxSize size( item->GetMinSizeWithBorder() );
85e5cfc9 1493 int minSize;
8b2bac62 1494
f98de448 1495 // Integer division rounded up is (a + b - 1) / b
85e5cfc9
VZ
1496 // Round up needed in order to guarantee that all
1497 // all items will have size not less then their min size
f98de448 1498 if (m_orient == wxHORIZONTAL)
85e5cfc9 1499 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
f98de448 1500 else
85e5cfc9 1501 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
8b2bac62 1502
85e5cfc9
VZ
1503 if (minSize > maxMinSize)
1504 maxMinSize = minSize;
f98de448 1505 }
12a3f227 1506 node = node->GetNext();
f98de448 1507 }
12a3f227 1508
4f469fb5
RR
1509 // Calculate overall minimum size
1510 node = m_children.GetFirst();
f98de448 1511 while (node)
61d514bb 1512 {
85e5cfc9 1513 wxSizerItem *item = node->GetData();
12a3f227 1514
2b5f62a0 1515 if (item->IsShown())
f98de448 1516 {
ba763a45 1517 wxSize size( item->GetMinSizeWithBorder() );
12a3f227 1518 if (item->GetProportion() != 0)
2b5f62a0
VZ
1519 {
1520 if (m_orient == wxHORIZONTAL)
85e5cfc9 1521 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
2b5f62a0 1522 else
85e5cfc9 1523 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
3ca6a5f0
BP
1524 }
1525 else
2b5f62a0
VZ
1526 {
1527 if (m_orient == wxVERTICAL)
1528 {
1529 m_fixedHeight += size.y;
1530 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1531 }
1532 else
1533 {
1534 m_fixedWidth += size.x;
1535 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1536 }
1537 }
85e5cfc9
VZ
1538
1539 if (m_orient == wxHORIZONTAL)
1540 {
1541 m_minWidth += size.x;
1542 m_minHeight = wxMax( m_minHeight, size.y );
1543 }
1544 else
1545 {
1546 m_minHeight += size.y;
1547 m_minWidth = wxMax( m_minWidth, size.x );
1548 }
2b5f62a0 1549 }
12a3f227 1550 node = node->GetNext();
61d514bb 1551 }
0c0d686f 1552
61d514bb
RR
1553 return wxSize( m_minWidth, m_minHeight );
1554}
27ea1d8a
RR
1555
1556//---------------------------------------------------------------------------
1557// wxStaticBoxSizer
1558//---------------------------------------------------------------------------
1559
1e6feb95
VZ
1560#if wxUSE_STATBOX
1561
27ea1d8a 1562wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
12a3f227
RL
1563 : wxBoxSizer( orient )
1564 , m_staticBox( box )
27ea1d8a 1565{
223d09f6 1566 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
27ea1d8a 1567}
0c0d686f 1568
6c1635b5
VZ
1569wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1570 : wxBoxSizer(orient),
1571 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1572{
1573}
1574
12a3f227
RL
1575static void GetStaticBoxBorders( wxStaticBox *box,
1576 int *borderTop,
1577 int *borderOther)
84028727
VZ
1578{
1579 // this has to be done platform by platform as there is no way to
1580 // guess the thickness of a wxStaticBox border
5dd070c2 1581 box->GetBordersForSizer(borderTop, borderOther);
84028727
VZ
1582}
1583
27ea1d8a
RR
1584void wxStaticBoxSizer::RecalcSizes()
1585{
84028727
VZ
1586 int top_border, other_border;
1587 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
27ea1d8a
RR
1588
1589 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 1590
27ea1d8a
RR
1591 wxPoint old_pos( m_position );
1592 m_position.x += other_border;
1593 m_position.y += top_border;
1594 wxSize old_size( m_size );
1595 m_size.x -= 2*other_border;
1596 m_size.y -= top_border + other_border;
0c0d686f 1597
27ea1d8a 1598 wxBoxSizer::RecalcSizes();
0c0d686f 1599
27ea1d8a
RR
1600 m_position = old_pos;
1601 m_size = old_size;
1602}
1603
1604wxSize wxStaticBoxSizer::CalcMin()
1605{
84028727
VZ
1606 int top_border, other_border;
1607 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
0c0d686f 1608
27ea1d8a 1609 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 1610 ret.x += 2*other_border;
27ea1d8a 1611 ret.y += other_border + top_border;
0c0d686f 1612
27ea1d8a
RR
1613 return ret;
1614}
83edc0a5 1615
eb2a7883
VZ
1616void wxStaticBoxSizer::ShowItems( bool show )
1617{
1618 m_staticBox->Show( show );
1619 wxBoxSizer::ShowItems( show );
1620}
1621
1e6feb95
VZ
1622#endif // wxUSE_STATBOX
1623
974c2a59
WS
1624#if wxUSE_BUTTON
1625
acf2ac37
RR
1626wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1627 : wxBoxSizer(wxHORIZONTAL)
1628{
94f53923
JS
1629 // Vertical buttons with lots of space on either side
1630 // looks rubbish on WinCE, so let's not do this for now.
1631 // If we are going to use vertical buttons, we should
1632 // put the sizer to the right of other controls in the dialog,
1633 // and that's beyond the scope of this sizer.
1634#ifndef __WXWINCE__
acf2ac37 1635 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
974c2a59 1636 // If we have a PDA screen, put yes/no button over
acf2ac37
RR
1637 // all other buttons, otherwise on the left side.
1638 if (is_pda)
1639 m_orient = wxVERTICAL;
94f53923 1640#endif
974c2a59 1641
acf2ac37
RR
1642 m_buttonAffirmative = NULL;
1643 m_buttonApply = NULL;
1644 m_buttonNegative = NULL;
1645 m_buttonCancel = NULL;
1646 m_buttonHelp = NULL;
1647}
1648
1649void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1650{
1651 switch (mybutton->GetId())
1652 {
1653 case wxID_OK:
1654 case wxID_YES:
1655 case wxID_SAVE:
1656 m_buttonAffirmative = mybutton;
1657 break;
1658 case wxID_APPLY:
1659 m_buttonApply = mybutton;
1660 break;
1661 case wxID_NO:
1662 m_buttonNegative = mybutton;
1663 break;
1664 case wxID_CANCEL:
1665 m_buttonCancel = mybutton;
1666 break;
1667 case wxID_HELP:
2997ca30 1668 case wxID_CONTEXT_HELP:
acf2ac37
RR
1669 m_buttonHelp = mybutton;
1670 break;
1671 default:
1672 break;
1673 }
1674}
1675
b181a505
RR
1676void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1677{
1678 m_buttonAffirmative = button;
1679}
1680
1681void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1682{
1683 m_buttonNegative = button;
1684}
1685
1686void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1687{
1688 m_buttonCancel = button;
1689}
1690
718903fe 1691void wxStdDialogButtonSizer::Realize()
acf2ac37
RR
1692{
1693#ifdef __WXMAC__
1694 Add(0, 0, 0, wxLEFT, 6);
1695 if (m_buttonHelp)
974c2a59
WS
1696 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1697
acf2ac37
RR
1698 if (m_buttonNegative){
1699 // HIG POLICE BULLETIN - destructive buttons need extra padding
1700 // 24 pixels on either side
1701 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1702 }
974c2a59 1703
acf2ac37 1704 // extra whitespace between help/negative and cancel/ok buttons
974c2a59
WS
1705 Add(0, 0, 1, wxEXPAND, 0);
1706
acf2ac37
RR
1707 if (m_buttonCancel){
1708 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1709 // Cancel or help should be default
1710 // m_buttonCancel->SetDefaultButton();
1711 }
974c2a59
WS
1712
1713 // Ugh, Mac doesn't really have apply dialogs, so I'll just
acf2ac37
RR
1714 // figure the best place is between Cancel and OK
1715 if (m_buttonApply)
1716 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
974c2a59 1717
acf2ac37
RR
1718 if (m_buttonAffirmative){
1719 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
974c2a59 1720
acf2ac37
RR
1721 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1722 // these buttons have set labels under Mac so we should use them
1723 m_buttonAffirmative->SetLabel(_("Save"));
1724 m_buttonNegative->SetLabel(_("Don't Save"));
1725 }
1726 }
974c2a59 1727
acf2ac37
RR
1728 // Extra space around and at the right
1729 Add(12, 24);
1730#elif defined(__WXGTK20__)
1731 Add(0, 0, 0, wxLEFT, 9);
1732 if (m_buttonHelp)
974c2a59
WS
1733 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1734
acf2ac37 1735 // extra whitespace between help and cancel/ok buttons
974c2a59
WS
1736 Add(0, 0, 1, wxEXPAND, 0);
1737
acf2ac37
RR
1738 if (m_buttonNegative){
1739 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1740 }
974c2a59 1741
acf2ac37
RR
1742 if (m_buttonCancel){
1743 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1744 // Cancel or help should be default
1745 // m_buttonCancel->SetDefaultButton();
1746 }
974c2a59 1747
acf2ac37
RR
1748 if (m_buttonApply)
1749 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
974c2a59 1750
acf2ac37
RR
1751 if (m_buttonAffirmative)
1752 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1753#else
1754 // do the same thing for GTK1 and Windows platforms
1755 // and assume any platform not accounted for here will use
1756 // Windows style
1757 Add(0, 0, 0, wxLEFT, 9);
1758 if (m_buttonHelp)
974c2a59
WS
1759 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1760
acf2ac37 1761 // extra whitespace between help and cancel/ok buttons
974c2a59 1762 Add(0, 0, 1, wxEXPAND, 0);
acf2ac37
RR
1763
1764 if (m_buttonApply)
1765 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
974c2a59 1766
acf2ac37
RR
1767 if (m_buttonAffirmative){
1768 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1769 }
974c2a59 1770
acf2ac37
RR
1771 if (m_buttonNegative){
1772 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1773 }
974c2a59 1774
acf2ac37
RR
1775 if (m_buttonCancel){
1776 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
1777 // Cancel or help should be default
1778 // m_buttonCancel->SetDefaultButton();
1779 }
974c2a59 1780
acf2ac37
RR
1781#endif
1782}
adbf2d73 1783
974c2a59
WS
1784#endif // wxUSE_BUTTON
1785
adbf2d73
VS
1786#if WXWIN_COMPATIBILITY_2_4
1787
ade4eb65 1788// ----------------------------------------------------------------------------
83edc0a5 1789// wxNotebookSizer
ade4eb65 1790// ----------------------------------------------------------------------------
83edc0a5 1791
adbf2d73
VS
1792#if wxUSE_BOOKCTRL
1793IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1794#if wxUSE_NOTEBOOK
1795IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1796#endif // wxUSE_NOTEBOOK
1797#endif // wxUSE_BOOKCTRL
1798
ade4eb65 1799#if wxUSE_BOOKCTRL
60be2f47 1800
61c083e7 1801wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
ade4eb65 1802 : m_bookctrl(bookctrl)
83edc0a5 1803{
ade4eb65 1804 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
83edc0a5
RR
1805}
1806
ade4eb65 1807void wxBookCtrlSizer::RecalcSizes()
83edc0a5 1808{
ade4eb65 1809 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
83edc0a5
RR
1810}
1811
ade4eb65 1812wxSize wxBookCtrlSizer::CalcMin()
83edc0a5 1813{
c47addef 1814 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
1e6feb95
VZ
1815
1816 sizeBorder.x += 5;
1817 sizeBorder.y += 5;
3ca6a5f0 1818
ade4eb65 1819 if ( m_bookctrl->GetPageCount() == 0 )
1e6feb95
VZ
1820 {
1821 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1822 }
83edc0a5
RR
1823
1824 int maxX = 0;
1825 int maxY = 0;
1826
ade4eb65
VZ
1827 wxWindowList::compatibility_iterator
1828 node = m_bookctrl->GetChildren().GetFirst();
83edc0a5
RR
1829 while (node)
1830 {
1831 wxWindow *item = node->GetData();
3ca6a5f0
BP
1832 wxSizer *itemsizer = item->GetSizer();
1833
1834 if (itemsizer)
1835 {
83edc0a5 1836 wxSize subsize( itemsizer->CalcMin() );
83edc0a5 1837
1e6feb95
VZ
1838 if (subsize.x > maxX)
1839 maxX = subsize.x;
1840 if (subsize.y > maxY)
1841 maxY = subsize.y;
3ca6a5f0
BP
1842 }
1843
1844 node = node->GetNext();
83edc0a5
RR
1845 }
1846
1e6feb95 1847 return wxSize( maxX, maxY ) + sizeBorder;
83edc0a5
RR
1848}
1849
2d480e40
RD
1850#if wxUSE_NOTEBOOK
1851
1852wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
2d480e40 1853{
adbf2d73
VS
1854 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
1855 m_bookctrl = nb;
2d480e40
RD
1856}
1857
1858#endif // wxUSE_NOTEBOOOK
ade4eb65 1859#endif // wxUSE_BOOKCTRL
34c3ffca 1860
adbf2d73 1861#endif // WXWIN_COMPATIBILITY_2_4