]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
Split this out from other changes to keep things sane..
[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_ABSTRACT_CLASS(wxSizerItem, wxObject)
33 IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject)
34 IMPLEMENT_ABSTRACT_CLASS(wxGridSizer, wxSizer)
35 IMPLEMENT_ABSTRACT_CLASS(wxFlexGridSizer, wxGridSizer)
36 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer)
37 #if wxUSE_STATBOX
38 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer)
39 #endif
40 #if wxUSE_NOTEBOOK
41 IMPLEMENT_ABSTRACT_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()
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()
236 {
237 return (m_window != NULL);
238 }
239
240 bool wxSizerItem::IsSizer()
241 {
242 return (m_sizer != NULL);
243 }
244
245 bool wxSizerItem::IsSpacer()
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( size_t index )
403 {
404 wxCHECK_MSG( 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 return m_children.DeleteNode( node );
413 }
414
415 bool wxSizer::Detach( wxSizer *sizer )
416 {
417 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
418
419 wxSizerItemList::Node *node = m_children.GetFirst();
420 while (node)
421 {
422 wxSizerItem *item = node->GetData();
423
424 if (item->GetSizer() == sizer)
425 {
426 item->DetachSizer();
427 return m_children.DeleteNode( node );
428 }
429 node = node->GetNext();
430 }
431
432 return false;
433 }
434
435 bool wxSizer::Detach( wxWindow *window )
436 {
437 wxASSERT_MSG( window, _T("Detaching NULL window") );
438
439 wxSizerItemList::Node *node = m_children.GetFirst();
440 while (node)
441 {
442 wxSizerItem *item = node->GetData();
443
444 if (item->GetWindow() == window)
445 {
446 item->GetWindow()->SetContainingSizer( NULL );
447 return m_children.DeleteNode( node );
448 }
449 node = node->GetNext();
450 }
451
452 return false;
453 }
454
455 bool wxSizer::Detach( size_t index )
456 {
457 wxCHECK_MSG( index < m_children.GetCount(),
458 false,
459 _T("Detach index is out of range") );
460
461 wxSizerItemList::Node *node = m_children.Item( index );
462
463 wxCHECK_MSG( node, false, _T("Failed to find child node") );
464
465 node->GetData()->DetachSizer();
466
467 return m_children.DeleteNode( node );
468 }
469
470 void wxSizer::Clear( bool delete_windows )
471 {
472 // First clear the ContainingSizer pointers
473 wxSizerItemList::Node *node = m_children.GetFirst();
474 while (node)
475 {
476 wxSizerItem *item = node->GetData();
477
478 if (item->IsWindow())
479 item->GetWindow()->SetContainingSizer( NULL );
480 node = node->GetNext();
481 }
482
483 // Destroy the windows if needed
484 if (delete_windows)
485 DeleteWindows();
486
487 // Now empty the list
488 m_children.Clear();
489 }
490
491 void wxSizer::DeleteWindows()
492 {
493 wxSizerItemList::Node *node = m_children.GetFirst();
494 while (node)
495 {
496 wxSizerItem *item = node->GetData();
497
498 item->DeleteWindows();
499 node = node->GetNext();
500 }
501 }
502
503 wxSize wxSizer::Fit( wxWindow *window )
504 {
505 wxSize size;
506 if (window->IsTopLevel())
507 size = FitSize( window );
508 else
509 size = GetMinWindowSize( window );
510
511 window->SetSize( size );
512
513 return size;
514 }
515
516 void wxSizer::FitInside( wxWindow *window )
517 {
518 wxSize size;
519 if (window->IsTopLevel())
520 size = VirtualFitSize( window );
521 else
522 size = GetMinClientSize( window );
523
524 window->SetVirtualSize( size );
525 }
526
527 void wxSizer::Layout()
528 {
529 CalcMin();
530 RecalcSizes();
531 }
532
533 void wxSizer::SetSizeHints( wxWindow *window )
534 {
535 // Preserve the window's max size hints, but set the
536 // lower bound according to the sizer calculations.
537
538 wxSize size = Fit( window );
539
540 window->SetSizeHints( size.x,
541 size.y,
542 window->GetMaxWidth(),
543 window->GetMaxHeight() );
544 }
545
546 void wxSizer::SetVirtualSizeHints( wxWindow *window )
547 {
548 // Preserve the window's max size hints, but set the
549 // lower bound according to the sizer calculations.
550
551 FitInside( window );
552 wxSize size( window->GetVirtualSize() );
553 window->SetVirtualSizeHints( size.x,
554 size.y,
555 window->GetMaxWidth(),
556 window->GetMaxHeight() );
557 }
558
559 wxSize wxSizer::GetMaxWindowSize( wxWindow *window )
560 {
561 return window->GetMaxSize();
562 }
563
564 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
565 {
566 wxSize minSize( GetMinSize() );
567 wxSize size( window->GetSize() );
568 wxSize client_size( window->GetClientSize() );
569
570 return wxSize( minSize.x+size.x-client_size.x,
571 minSize.y+size.y-client_size.y );
572 }
573
574 // Return a window size that will fit within the screens dimensions
575 wxSize wxSizer::FitSize( wxWindow *window )
576 {
577 wxSize size = GetMinWindowSize( window );
578 wxSize sizeMax = GetMaxWindowSize( window );
579
580 // Limit the size if sizeMax != wxDefaultSize
581
582 if ( size.x > sizeMax.x && sizeMax.x != -1 )
583 size.x = sizeMax.x;
584 if ( size.y > sizeMax.y && sizeMax.y != -1 )
585 size.y = sizeMax.y;
586
587 return size;
588 }
589
590 wxSize wxSizer::GetMaxClientSize( wxWindow *window )
591 {
592 wxSize maxSize( window->GetMaxSize() );
593
594 if( maxSize != wxDefaultSize )
595 {
596 wxSize size( window->GetSize() );
597 wxSize client_size( window->GetClientSize() );
598
599 return wxSize( maxSize.x + client_size.x - size.x,
600 maxSize.y + client_size.y - size.y );
601 }
602 else
603 return wxDefaultSize;
604 }
605
606 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
607 {
608 return GetMinSize(); // Already returns client size.
609 }
610
611 wxSize wxSizer::VirtualFitSize( wxWindow *window )
612 {
613 wxSize size = GetMinClientSize( window );
614 wxSize sizeMax = GetMaxClientSize( window );
615
616 // Limit the size if sizeMax != wxDefaultSize
617
618 if ( size.x > sizeMax.x && sizeMax.x != -1 )
619 size.x = sizeMax.x;
620 if ( size.y > sizeMax.y && sizeMax.y != -1 )
621 size.y = sizeMax.y;
622
623 return size;
624 }
625
626 void wxSizer::SetDimension( int x, int y, int width, int height )
627 {
628 m_position.x = x;
629 m_position.y = y;
630 m_size.x = width;
631 m_size.y = height;
632 Layout();
633 }
634
635 wxSize wxSizer::GetMinSize()
636 {
637 wxSize ret( CalcMin() );
638 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
639 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
640 return ret;
641 }
642
643 void wxSizer::DoSetMinSize( int width, int height )
644 {
645 m_minSize.x = width;
646 m_minSize.y = height;
647 }
648
649 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
650 {
651 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
652
653 // Is it our immediate child?
654
655 wxSizerItemList::Node *node = m_children.GetFirst();
656 while (node)
657 {
658 wxSizerItem *item = node->GetData();
659
660 if (item->GetWindow() == window)
661 {
662 item->SetInitSize( width, height );
663 return true;
664 }
665 node = node->GetNext();
666 }
667
668 // No? Search any subsizers we own then
669
670 node = m_children.GetFirst();
671 while (node)
672 {
673 wxSizerItem *item = node->GetData();
674
675 if ( item->GetSizer() &&
676 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
677 {
678 // A child sizer found the requested windw, exit.
679 return true;
680 }
681 node = node->GetNext();
682 }
683
684 return false;
685 }
686
687 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
688 {
689 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
690
691 // Is it our immediate child?
692
693 wxSizerItemList::Node *node = m_children.GetFirst();
694 while (node)
695 {
696 wxSizerItem *item = node->GetData();
697
698 if (item->GetSizer() == sizer)
699 {
700 item->GetSizer()->DoSetMinSize( width, height );
701 return true;
702 }
703 node = node->GetNext();
704 }
705
706 // No? Search any subsizers we own then
707
708 node = m_children.GetFirst();
709 while (node)
710 {
711 wxSizerItem *item = node->GetData();
712
713 if ( item->GetSizer() &&
714 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
715 {
716 // A child found the requested sizer, exit.
717 return true;
718 }
719 node = node->GetNext();
720 }
721
722 return false;
723 }
724
725 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
726 {
727 wxSizerItemList::Node *node = m_children.Item( index );
728
729 wxCHECK_MSG( node, false, _T("Failed to find child node") );
730
731 wxSizerItem *item = node->GetData();
732
733 if (item->GetSizer())
734 {
735 // Sizers contains the minimal size in them, if not calculated ...
736 item->GetSizer()->DoSetMinSize( width, height );
737 }
738 else
739 {
740 // ... but the minimal size of spacers and windows in stored in them
741 item->SetInitSize( width, height );
742 }
743
744 return true;
745 }
746
747 void wxSizer::Show( wxWindow *window, bool show )
748 {
749 wxASSERT_MSG( window, _T("Show for NULL window") );
750
751 wxSizerItemList::Node *node = m_children.GetFirst();
752 while (node)
753 {
754 wxSizerItem *item = node->GetData();
755
756 if (item->GetWindow() == window)
757 {
758 item->Show( show );
759 break;
760 }
761 node = node->GetNext();
762 }
763 }
764
765 void wxSizer::Show( wxSizer *sizer, bool show )
766 {
767 wxASSERT_MSG( sizer, _T("Show for NULL sizer") );
768
769 wxSizerItemList::Node *node = m_children.GetFirst();
770 while (node)
771 {
772 wxSizerItem *item = node->GetData();
773
774 if (item->GetSizer() == sizer)
775 {
776 item->Show( show );
777 break;
778 }
779 node = node->GetNext();
780 }
781 }
782
783 void wxSizer::Show( size_t index, bool show )
784 {
785 wxCHECK_RET( index < m_children.GetCount(),
786 _T("Show index is out of range") );
787
788 m_children.Item( index )->GetData()->Show( show );
789 }
790
791 void wxSizer::ShowItems( bool show )
792 {
793 wxSizerItemList::Node *node = m_children.GetFirst();
794 while (node)
795 {
796 node->GetData()->Show( show );
797 node = node->GetNext();
798 }
799 }
800
801 bool wxSizer::IsShown( wxWindow *window )
802 {
803 wxSizerItemList::Node *node = m_children.GetFirst();
804 while (node)
805 {
806 wxSizerItem *item = node->GetData();
807
808 if (item->GetWindow() == window)
809 {
810 return item->IsShown();
811 }
812 node = node->GetNext();
813 }
814
815 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
816
817 return false;
818 }
819
820 bool wxSizer::IsShown( wxSizer *sizer )
821 {
822 wxSizerItemList::Node *node = m_children.GetFirst();
823 while (node)
824 {
825 wxSizerItem *item = node->GetData();
826
827 if (item->GetSizer() == sizer)
828 {
829 return item->IsShown();
830 }
831 node = node->GetNext();
832 }
833
834 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
835
836 return false;
837 }
838
839 bool wxSizer::IsShown( size_t index )
840 {
841 wxCHECK_MSG( index < m_children.GetCount(),
842 false,
843 _T("IsShown index is out of range") );
844
845 return m_children.Item( index )->GetData()->IsShown();
846 }
847
848
849 //---------------------------------------------------------------------------
850 // wxGridSizer
851 //---------------------------------------------------------------------------
852
853 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
854 : m_rows( rows )
855 , m_cols( cols )
856 , m_vgap( vgap )
857 , m_hgap( hgap )
858 {
859 }
860
861 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
862 : m_rows( 0 )
863 , m_cols( cols )
864 , m_vgap( vgap )
865 , m_hgap( hgap )
866 {
867 }
868
869 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
870 {
871 int nitems = m_children.GetCount();
872 if ( nitems)
873 {
874 if ( m_cols )
875 {
876 ncols = m_cols;
877 nrows = (nitems + m_cols - 1) / m_cols;
878 }
879 else if ( m_rows )
880 {
881 ncols = (nitems + m_rows - 1) / m_rows;
882 nrows = m_rows;
883 }
884 else // 0 columns, 0 rows?
885 {
886 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
887
888 nrows = ncols = 0;
889 }
890 }
891
892 return nitems;
893 }
894
895 void wxGridSizer::RecalcSizes()
896 {
897 int nitems, nrows, ncols;
898 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
899 return;
900
901 wxSize sz( GetSize() );
902 wxPoint pt( GetPosition() );
903
904 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
905 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
906
907 int x = pt.x;
908 for (int c = 0; c < ncols; c++)
909 {
910 int y = pt.y;
911 for (int r = 0; r < nrows; r++)
912 {
913 int i = r * ncols + c;
914 if (i < nitems)
915 {
916 wxSizerItemList::Node *node = m_children.Item( i );
917
918 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
919
920 SetItemBounds( node->GetData(), x, y, w, h);
921 }
922 y = y + h + m_vgap;
923 }
924 x = x + w + m_hgap;
925 }
926 }
927
928 wxSize wxGridSizer::CalcMin()
929 {
930 int nitems, nrows, ncols;
931 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
932 return wxSize(10, 10);
933
934 // Find the max width and height for any component
935 int w = 0;
936 int h = 0;
937
938 wxSizerItemList::Node *node = m_children.GetFirst();
939 while (node)
940 {
941 wxSizerItem *item = node->GetData();
942 wxSize sz( item->CalcMin() );
943
944 w = wxMax( w, sz.x );
945 h = wxMax( h, sz.y );
946
947 node = node->GetNext();
948 }
949
950 return wxSize( ncols * w + (ncols-1) * m_hgap,
951 nrows * h + (nrows-1) * m_vgap );
952 }
953
954 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
955 {
956 wxPoint pt( x,y );
957 wxSize sz( item->CalcMin() );
958 int flag = item->GetFlag();
959
960 if ((flag & wxEXPAND) || (flag & wxSHAPED))
961 {
962 sz = wxSize(w, h);
963 }
964 else
965 {
966 if (flag & wxALIGN_CENTER_HORIZONTAL)
967 {
968 pt.x = x + (w - sz.x) / 2;
969 }
970 else if (flag & wxALIGN_RIGHT)
971 {
972 pt.x = x + (w - sz.x);
973 }
974
975 if (flag & wxALIGN_CENTER_VERTICAL)
976 {
977 pt.y = y + (h - sz.y) / 2;
978 }
979 else if (flag & wxALIGN_BOTTOM)
980 {
981 pt.y = y + (h - sz.y);
982 }
983 }
984
985 item->SetDimension(pt, sz);
986 }
987
988 //---------------------------------------------------------------------------
989 // wxFlexGridSizer
990 //---------------------------------------------------------------------------
991
992 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
993 : wxGridSizer( rows, cols, vgap, hgap )
994 , m_rowHeights( NULL )
995 , m_colWidths( NULL )
996 {
997 }
998
999 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1000 : wxGridSizer( cols, vgap, hgap )
1001 , m_rowHeights( NULL )
1002 , m_colWidths( NULL )
1003 {
1004 }
1005
1006 wxFlexGridSizer::~wxFlexGridSizer()
1007 {
1008 if (m_rowHeights)
1009 delete[] m_rowHeights;
1010 if (m_colWidths)
1011 delete[] m_colWidths;
1012 }
1013
1014 void wxFlexGridSizer::CreateArrays()
1015 {
1016 if (m_rowHeights)
1017 delete[] m_rowHeights;
1018 if (m_colWidths)
1019 delete[] m_colWidths;
1020
1021 int nitems, nrows, ncols;
1022 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1023 {
1024 m_rowHeights =
1025 m_colWidths = NULL;
1026 }
1027
1028 m_rowHeights = new int[nrows];
1029 m_colWidths = new int[ncols];
1030
1031 for (int col = 0; col < ncols; col++)
1032 m_colWidths[ col ] = 0;
1033 for (int row = 0; row < nrows; row++)
1034 m_rowHeights[ row ] = 0;
1035 }
1036
1037 void 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 int delta;
1047 size_t idx,num;
1048 wxArrayInt temp;
1049
1050 // Transfer only those rows into temp which exist in the sizer
1051 // ignoring the superflouus ones. This prevents a segfault when
1052 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
1053 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1054 if (m_growableRows[idx] < nrows)
1055 temp.Add( m_growableRows[idx] );
1056 num = temp.GetCount();
1057
1058 if ((num > 0) && (sz.y > minsz.y))
1059 {
1060 delta = (sz.y - minsz.y) / num;
1061 for (idx = 0; idx < num; idx++)
1062 m_rowHeights[ temp[idx] ] += delta;
1063 }
1064
1065 temp.Empty();
1066 // See above
1067 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1068 if (m_growableCols[idx] < ncols)
1069 temp.Add( m_growableCols[idx] );
1070 num = temp.GetCount();
1071
1072 if ((num > 0) && (sz.x > minsz.x))
1073 {
1074 delta = (sz.x - minsz.x) / num;
1075 for (idx = 0; idx < num; idx++)
1076 m_colWidths[ temp[idx] ] += delta;
1077 }
1078
1079 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1080
1081 int x = pt.x;
1082 for (int c = 0; c < ncols; c++)
1083 {
1084 int y = pt.y;
1085 for (int r = 0; r < nrows; r++)
1086 {
1087 int i = r * ncols + c;
1088 if (i < nitems)
1089 {
1090 wxSizerItemList::Node *node = m_children.Item( i );
1091
1092 wxASSERT_MSG( node, _T("Failed to find node") );
1093
1094 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1095 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1096
1097 SetItemBounds( node->GetData(), x, y, w, h);
1098 }
1099 y = y + m_rowHeights[r] + m_vgap;
1100 }
1101 x = x + m_colWidths[c] + m_hgap;
1102 }
1103 }
1104
1105 wxSize wxFlexGridSizer::CalcMin()
1106 {
1107 int nitems, nrows, ncols;
1108 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1109 return wxSize(10,10);
1110
1111 CreateArrays();
1112
1113 int i = 0;
1114 wxSizerItemList::Node *node = m_children.GetFirst();
1115
1116 while (node)
1117 {
1118 wxSizerItem *item = node->GetData();
1119 wxSize sz( item->CalcMin() );
1120 int row = i / ncols;
1121 int col = i % ncols;
1122
1123 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
1124 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
1125
1126 node = node->GetNext();
1127 i++;
1128 }
1129
1130 int width = 0;
1131 for (int col = 0; col < ncols; col++)
1132 width += m_colWidths[ col ];
1133
1134 int height = 0;
1135 for (int row = 0; row < nrows; row++)
1136 height += m_rowHeights[ row ];
1137
1138 return wxSize( width + (ncols-1) * m_hgap,
1139 height + (nrows-1) * m_vgap);
1140 }
1141
1142 void wxFlexGridSizer::AddGrowableRow( size_t idx )
1143 {
1144 m_growableRows.Add( idx );
1145 }
1146
1147 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
1148 {
1149 }
1150
1151 void wxFlexGridSizer::AddGrowableCol( size_t idx )
1152 {
1153 m_growableCols.Add( idx );
1154 }
1155
1156 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
1157 {
1158 }
1159
1160 //---------------------------------------------------------------------------
1161 // wxBoxSizer
1162 //---------------------------------------------------------------------------
1163
1164 wxBoxSizer::wxBoxSizer( int orient )
1165 : m_orient( orient )
1166 {
1167 }
1168
1169 void wxBoxSizer::RecalcSizes()
1170 {
1171 if (m_children.GetCount() == 0)
1172 return;
1173
1174 int delta = 0;
1175 int extra = 0;
1176 if (m_stretchable)
1177 {
1178 if (m_orient == wxHORIZONTAL)
1179 {
1180 delta = (m_size.x - m_fixedWidth) / m_stretchable;
1181 extra = (m_size.x - m_fixedWidth) % m_stretchable;
1182 }
1183 else
1184 {
1185 delta = (m_size.y - m_fixedHeight) / m_stretchable;
1186 extra = (m_size.y - m_fixedHeight) % m_stretchable;
1187 }
1188 }
1189
1190 wxPoint pt( m_position );
1191
1192 wxSizerItemList::Node *node = m_children.GetFirst();
1193 while (node)
1194 {
1195 wxSizerItem *item = node->GetData();
1196
1197 if (item->IsShown())
1198 {
1199 int weight = 1;
1200 if (item->GetProportion())
1201 weight = item->GetProportion();
1202
1203 wxSize size( item->CalcMin() );
1204
1205 if (m_orient == wxVERTICAL)
1206 {
1207 wxCoord height = size.y;
1208 if (item->GetProportion())
1209 {
1210 height = (delta * weight) + extra;
1211 extra = 0; // only the first item will get the remainder as extra size
1212 }
1213
1214 wxPoint child_pos( pt );
1215 wxSize child_size( wxSize( size.x, height) );
1216
1217 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1218 child_size.x = m_size.x;
1219 else if (item->GetFlag() & wxALIGN_RIGHT)
1220 child_pos.x += m_size.x - size.x;
1221 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1222 // XXX wxCENTER is added for backward compatibility;
1223 // wxALIGN_CENTER should be used in new code
1224 child_pos.x += (m_size.x - size.x) / 2;
1225
1226 item->SetDimension( child_pos, child_size );
1227
1228 pt.y += height;
1229 }
1230 else
1231 {
1232 wxCoord width = size.x;
1233 if (item->GetProportion())
1234 {
1235 width = (delta * weight) + extra;
1236 extra = 0; // only the first item will get the remainder as extra size
1237 }
1238
1239 wxPoint child_pos( pt );
1240 wxSize child_size( wxSize(width, size.y) );
1241
1242 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1243 child_size.y = m_size.y;
1244 else if (item->GetFlag() & wxALIGN_BOTTOM)
1245 child_pos.y += m_size.y - size.y;
1246 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1247 // XXX wxCENTER is added for backward compatibility;
1248 // wxALIGN_CENTER should be used in new code
1249 child_pos.y += (m_size.y - size.y) / 2;
1250
1251 item->SetDimension( child_pos, child_size );
1252
1253 pt.x += width;
1254 }
1255 }
1256
1257 node = node->GetNext();
1258 }
1259 }
1260
1261 wxSize wxBoxSizer::CalcMin()
1262 {
1263 if (m_children.GetCount() == 0)
1264 return wxSize(10,10);
1265
1266 m_stretchable = 0;
1267 m_minWidth = 0;
1268 m_minHeight = 0;
1269 m_fixedWidth = 0;
1270 m_fixedHeight = 0;
1271
1272 // Find how long each stretch unit needs to be
1273 int stretchSize = 1;
1274 wxSizerItemList::Node *node = m_children.GetFirst();
1275
1276 while (node)
1277 {
1278 wxSizerItem *item = node->GetData();
1279
1280 if (item->IsShown() && item->GetProportion() != 0)
1281 {
1282 int stretch = item->GetProportion();
1283 wxSize size( item->CalcMin() );
1284 int sizePerStretch;
1285 // Integer division rounded up is (a + b - 1) / b
1286 if (m_orient == wxHORIZONTAL)
1287 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1288 else
1289 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1290 if (sizePerStretch > stretchSize)
1291 stretchSize = sizePerStretch;
1292 }
1293 node = node->GetNext();
1294 }
1295
1296 // Calculate overall minimum size
1297 node = m_children.GetFirst();
1298 while (node)
1299 {
1300 wxSizerItem *item = node->GetData();
1301
1302 if (item->IsShown())
1303 {
1304 m_stretchable += item->GetProportion();
1305
1306 wxSize size( item->CalcMin() );
1307 if (item->GetProportion() != 0)
1308 {
1309 if (m_orient == wxHORIZONTAL)
1310 size.x = stretchSize * item->GetProportion();
1311 else
1312 size.y = stretchSize * item->GetProportion();
1313 }
1314
1315 if (m_orient == wxHORIZONTAL)
1316 {
1317 m_minWidth += size.x;
1318 m_minHeight = wxMax( m_minHeight, size.y );
1319 }
1320 else
1321 {
1322 m_minHeight += size.y;
1323 m_minWidth = wxMax( m_minWidth, size.x );
1324 }
1325
1326 if (item->GetProportion() == 0)
1327 {
1328 if (m_orient == wxVERTICAL)
1329 {
1330 m_fixedHeight += size.y;
1331 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1332 }
1333 else
1334 {
1335 m_fixedWidth += size.x;
1336 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1337 }
1338 }
1339 }
1340 node = node->GetNext();
1341 }
1342
1343 return wxSize( m_minWidth, m_minHeight );
1344 }
1345
1346 //---------------------------------------------------------------------------
1347 // wxStaticBoxSizer
1348 //---------------------------------------------------------------------------
1349
1350 #if wxUSE_STATBOX
1351
1352 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1353 : wxBoxSizer( orient )
1354 , m_staticBox( box )
1355 {
1356 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1357 }
1358
1359 static void GetStaticBoxBorders( wxStaticBox *box,
1360 int *borderTop,
1361 int *borderOther)
1362 {
1363 // this has to be done platform by platform as there is no way to
1364 // guess the thickness of a wxStaticBox border
1365 #ifdef __WXGTK__
1366 if ( box->GetLabel().IsEmpty() )
1367 *borderTop = 5;
1368 else
1369 #endif // __WXGTK__
1370 *borderTop = 15;
1371 (void)box;
1372 *borderOther = 5;
1373 }
1374
1375 void wxStaticBoxSizer::RecalcSizes()
1376 {
1377 int top_border, other_border;
1378 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1379
1380 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1381
1382 wxPoint old_pos( m_position );
1383 m_position.x += other_border;
1384 m_position.y += top_border;
1385 wxSize old_size( m_size );
1386 m_size.x -= 2*other_border;
1387 m_size.y -= top_border + other_border;
1388
1389 wxBoxSizer::RecalcSizes();
1390
1391 m_position = old_pos;
1392 m_size = old_size;
1393 }
1394
1395 wxSize wxStaticBoxSizer::CalcMin()
1396 {
1397 int top_border, other_border;
1398 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1399
1400 wxSize ret( wxBoxSizer::CalcMin() );
1401 ret.x += 2*other_border;
1402 ret.y += other_border + top_border;
1403
1404 return ret;
1405 }
1406
1407 #endif // wxUSE_STATBOX
1408
1409 //---------------------------------------------------------------------------
1410 // wxNotebookSizer
1411 //---------------------------------------------------------------------------
1412
1413 #if wxUSE_NOTEBOOK
1414
1415 wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
1416 : m_notebook( nb )
1417 {
1418 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
1419 }
1420
1421 void wxNotebookSizer::RecalcSizes()
1422 {
1423 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1424 }
1425
1426 wxSize wxNotebookSizer::CalcMin()
1427 {
1428 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1429
1430 sizeBorder.x += 5;
1431 sizeBorder.y += 5;
1432
1433 if (m_notebook->GetChildren().GetCount() == 0)
1434 {
1435 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1436 }
1437
1438 int maxX = 0;
1439 int maxY = 0;
1440
1441 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1442 while (node)
1443 {
1444 wxWindow *item = node->GetData();
1445 wxSizer *itemsizer = item->GetSizer();
1446
1447 if (itemsizer)
1448 {
1449 wxSize subsize( itemsizer->CalcMin() );
1450
1451 if (subsize.x > maxX)
1452 maxX = subsize.x;
1453 if (subsize.y > maxY)
1454 maxY = subsize.y;
1455 }
1456
1457 node = node->GetNext();
1458 }
1459
1460 return wxSize( maxX, maxY ) + sizeBorder;
1461 }
1462
1463 #endif // wxUSE_NOTEBOOK
1464
1465 // vi:sts=4:sw=4:et