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