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