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