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