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