]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
wxPickerBase derives from wxControl, not wxWindow
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/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 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17 #pragma hdrstop
18 #endif
19
20 #include "wx/sizer.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/string.h"
24 #include "wx/intl.h"
25 #include "wx/math.h"
26 #include "wx/utils.h"
27 #include "wx/settings.h"
28 #include "wx/statbox.h"
29 #endif // WX_PRECOMP
30
31 #include "wx/listimpl.cpp"
32
33 #if WXWIN_COMPATIBILITY_2_4
34 #include "wx/notebook.h"
35 #endif
36
37 //---------------------------------------------------------------------------
38
39 IMPLEMENT_CLASS(wxSizerItem, wxObject)
40 IMPLEMENT_CLASS(wxSizer, wxObject)
41 IMPLEMENT_CLASS(wxGridSizer, wxSizer)
42 IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
43 IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
44 #if wxUSE_STATBOX
45 IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
46 #endif
47 #if wxUSE_BUTTON
48 IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
49 #endif
50
51 WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
52
53 /*
54 TODO PROPERTIES
55 sizeritem
56 object
57 object_ref
58 minsize
59 option
60 flag
61 border
62 spacer
63 option
64 flag
65 borfder
66 boxsizer
67 orient
68 staticboxsizer
69 orient
70 label
71 gridsizer
72 rows
73 cols
74 vgap
75 hgap
76 flexgridsizer
77 rows
78 cols
79 vgap
80 hgap
81 growablerows
82 growablecols
83 minsize
84 */
85
86 // ----------------------------------------------------------------------------
87 // wxSizerItem
88 // ----------------------------------------------------------------------------
89
90 void wxSizerItem::Init(const wxSizerFlags& flags)
91 {
92 Init();
93
94 m_proportion = flags.GetProportion();
95 m_flag = flags.GetFlags();
96 m_border = flags.GetBorderInPixels();
97 }
98
99 wxSizerItem::wxSizerItem()
100 {
101 Init();
102
103 m_proportion = 0;
104 m_border = 0;
105 m_flag = 0;
106
107 m_kind = Item_None;
108 }
109
110 // window item
111 void wxSizerItem::SetWindow(wxWindow *window)
112 {
113 wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") );
114
115 m_kind = Item_Window;
116 m_window = window;
117
118 // window doesn't become smaller than its initial size, whatever happens
119 m_minSize = window->GetSize();
120
121 if ( m_flag & wxFIXED_MINSIZE )
122 window->SetMinSize(m_minSize);
123
124 // aspect ratio calculated from initial size
125 SetRatio(m_minSize);
126 }
127
128 wxSizerItem::wxSizerItem(wxWindow *window,
129 int proportion,
130 int flag,
131 int border,
132 wxObject* userData)
133 : m_proportion(proportion),
134 m_border(border),
135 m_flag(flag),
136 m_userData(userData)
137 {
138 SetWindow(window);
139 }
140
141 // sizer item
142 void wxSizerItem::SetSizer(wxSizer *sizer)
143 {
144 m_kind = Item_Sizer;
145 m_sizer = sizer;
146 }
147
148 wxSizerItem::wxSizerItem(wxSizer *sizer,
149 int proportion,
150 int flag,
151 int border,
152 wxObject* userData)
153 : m_proportion(proportion),
154 m_border(border),
155 m_flag(flag),
156 m_ratio(0.0),
157 m_userData(userData)
158 {
159 SetSizer(sizer);
160
161 // m_minSize is set later
162 }
163
164 // spacer item
165 void wxSizerItem::SetSpacer(const wxSize& size)
166 {
167 m_kind = Item_Spacer;
168 m_spacer = new wxSizerSpacer(size);
169 m_minSize = size;
170 SetRatio(size);
171 }
172
173 wxSizerItem::wxSizerItem(int width,
174 int height,
175 int proportion,
176 int flag,
177 int border,
178 wxObject* userData)
179 : m_minSize(width, height), // minimal size is the initial size
180 m_proportion(proportion),
181 m_border(border),
182 m_flag(flag),
183 m_userData(userData)
184 {
185 SetSpacer(width, height);
186 }
187
188 wxSizerItem::~wxSizerItem()
189 {
190 delete m_userData;
191
192 switch ( m_kind )
193 {
194 case Item_None:
195 break;
196
197 case Item_Window:
198 m_window->SetContainingSizer(NULL);
199 break;
200
201 case Item_Sizer:
202 delete m_sizer;
203 break;
204
205 case Item_Spacer:
206 delete m_spacer;
207 break;
208
209 case Item_Max:
210 default:
211 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
212 }
213 }
214
215 wxSize wxSizerItem::GetSpacer() const
216 {
217 wxSize size;
218 if ( m_kind == Item_Spacer )
219 size = m_spacer->GetSize();
220
221 return size;
222 }
223
224
225 wxSize wxSizerItem::GetSize() const
226 {
227 wxSize ret;
228 switch ( m_kind )
229 {
230 case Item_None:
231 break;
232
233 case Item_Window:
234 ret = m_window->GetSize();
235 break;
236
237 case Item_Sizer:
238 ret = m_sizer->GetSize();
239 break;
240
241 case Item_Spacer:
242 ret = m_spacer->GetSize();
243 break;
244
245 case Item_Max:
246 default:
247 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
248 }
249
250 if (m_flag & wxWEST)
251 ret.x += m_border;
252 if (m_flag & wxEAST)
253 ret.x += m_border;
254 if (m_flag & wxNORTH)
255 ret.y += m_border;
256 if (m_flag & wxSOUTH)
257 ret.y += m_border;
258
259 return ret;
260 }
261
262 wxSize wxSizerItem::CalcMin()
263 {
264 if (IsSizer())
265 {
266 m_minSize = m_sizer->GetMinSize();
267
268 // if we have to preserve aspect ratio _AND_ this is
269 // the first-time calculation, consider ret to be initial size
270 if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
271 SetRatio(m_minSize);
272 }
273 else if ( IsWindow() )
274 {
275 // Since the size of the window may change during runtime, we
276 // should use the current minimal/best size.
277 m_minSize = m_window->GetBestFittingSize();
278 }
279
280 return GetMinSizeWithBorder();
281 }
282
283 wxSize wxSizerItem::GetMinSizeWithBorder() const
284 {
285 wxSize ret = m_minSize;
286
287 if (m_flag & wxWEST)
288 ret.x += m_border;
289 if (m_flag & wxEAST)
290 ret.x += m_border;
291 if (m_flag & wxNORTH)
292 ret.y += m_border;
293 if (m_flag & wxSOUTH)
294 ret.y += m_border;
295
296 return ret;
297 }
298
299
300 void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
301 {
302 wxPoint pos = pos_;
303 wxSize size = size_;
304 if (m_flag & wxSHAPED)
305 {
306 // adjust aspect ratio
307 int rwidth = (int) (size.y * m_ratio);
308 if (rwidth > size.x)
309 {
310 // fit horizontally
311 int rheight = (int) (size.x / m_ratio);
312 // add vertical space
313 if (m_flag & wxALIGN_CENTER_VERTICAL)
314 pos.y += (size.y - rheight) / 2;
315 else if (m_flag & wxALIGN_BOTTOM)
316 pos.y += (size.y - rheight);
317 // use reduced dimensions
318 size.y =rheight;
319 }
320 else if (rwidth < size.x)
321 {
322 // add horizontal space
323 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
324 pos.x += (size.x - rwidth) / 2;
325 else if (m_flag & wxALIGN_RIGHT)
326 pos.x += (size.x - rwidth);
327 size.x = rwidth;
328 }
329 }
330
331 // This is what GetPosition() returns. Since we calculate
332 // borders afterwards, GetPosition() will be the left/top
333 // corner of the surrounding border.
334 m_pos = pos;
335
336 if (m_flag & wxWEST)
337 {
338 pos.x += m_border;
339 size.x -= m_border;
340 }
341 if (m_flag & wxEAST)
342 {
343 size.x -= m_border;
344 }
345 if (m_flag & wxNORTH)
346 {
347 pos.y += m_border;
348 size.y -= m_border;
349 }
350 if (m_flag & wxSOUTH)
351 {
352 size.y -= m_border;
353 }
354
355 m_rect = wxRect(pos, size);
356
357 switch ( m_kind )
358 {
359 case Item_None:
360 wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
361 break;
362
363 case Item_Window:
364 m_window->SetSize(pos.x, pos.y, size.x, size.y,
365 wxSIZE_ALLOW_MINUS_ONE);
366 break;
367
368 case Item_Sizer:
369 m_sizer->SetDimension(pos.x, pos.y, size.x, size.y);
370 break;
371
372 case Item_Spacer:
373 m_spacer->SetSize(size);
374 break;
375
376 case Item_Max:
377 default:
378 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
379 }
380 }
381
382 void wxSizerItem::DeleteWindows()
383 {
384 switch ( m_kind )
385 {
386 case Item_None:
387 case Item_Spacer:
388 break;
389
390 case Item_Window:
391 //We are deleting the window from this sizer - normally
392 //the window destroys the sizer associated with it,
393 //which might destroy this, which we don't want
394 m_window->SetContainingSizer(NULL);
395 m_window->Destroy();
396 //Putting this after the switch will result in a spacer
397 //not being deleted properly on destruction
398 m_kind = Item_None;
399 break;
400
401 case Item_Sizer:
402 m_sizer->DeleteWindows();
403 break;
404
405 case Item_Max:
406 default:
407 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
408 }
409
410 }
411
412 void wxSizerItem::Show( bool show )
413 {
414 switch ( m_kind )
415 {
416 case Item_None:
417 wxFAIL_MSG( _T("can't show uninitialized sizer item") );
418 break;
419
420 case Item_Window:
421 m_window->Show(show);
422 break;
423
424 case Item_Sizer:
425 m_sizer->Show(show);
426 break;
427
428 case Item_Spacer:
429 m_spacer->Show(show);
430 break;
431
432 case Item_Max:
433 default:
434 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
435 }
436 }
437
438 bool wxSizerItem::IsShown() const
439 {
440 switch ( m_kind )
441 {
442 case Item_None:
443 // we may be called from CalcMin(), just return false so that we're
444 // not used
445 break;
446
447 case Item_Window:
448 return m_window->IsShown();
449
450 case Item_Sizer:
451 // arbitrarily decide that if at least one of our elements is
452 // shown, so are we (this arbitrariness is the reason for
453 // deprecating this function)
454 {
455 for ( wxSizerItemList::compatibility_iterator
456 node = m_sizer->GetChildren().GetFirst();
457 node;
458 node = node->GetNext() )
459 {
460 if ( node->GetData()->IsShown() )
461 return true;
462 }
463 }
464 return false;
465
466 case Item_Spacer:
467 return m_spacer->IsShown();
468
469 case Item_Max:
470 default:
471 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
472 }
473
474 return false;
475 }
476
477 #if WXWIN_COMPATIBILITY_2_6
478 void wxSizerItem::SetOption( int option )
479 {
480 SetProportion( option );
481 }
482
483 int wxSizerItem::GetOption() const
484 {
485 return GetProportion();
486 }
487 #endif // WXWIN_COMPATIBILITY_2_6
488
489
490 //---------------------------------------------------------------------------
491 // wxSizer
492 //---------------------------------------------------------------------------
493
494 wxSizer::~wxSizer()
495 {
496 WX_CLEAR_LIST(wxSizerItemList, m_children);
497 }
498
499 wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
500 {
501 m_children.Insert( index, item );
502
503 if ( item->GetWindow() )
504 item->GetWindow()->SetContainingSizer( this );
505
506 return item;
507 }
508
509 #if WXWIN_COMPATIBILITY_2_6
510 bool wxSizer::Remove( wxWindow *window )
511 {
512 return Detach( window );
513 }
514 #endif // WXWIN_COMPATIBILITY_2_6
515
516 bool wxSizer::Remove( wxSizer *sizer )
517 {
518 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
519
520 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
521 while (node)
522 {
523 wxSizerItem *item = node->GetData();
524
525 if (item->GetSizer() == sizer)
526 {
527 delete item;
528 m_children.Erase( node );
529 return true;
530 }
531
532 node = node->GetNext();
533 }
534
535 return false;
536 }
537
538 bool wxSizer::Remove( int index )
539 {
540 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
541 false,
542 _T("Remove index is out of range") );
543
544 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
545
546 wxCHECK_MSG( node, false, _T("Failed to find child node") );
547
548 wxSizerItem *item = node->GetData();
549
550 if ( item->IsWindow() )
551 item->GetWindow()->SetContainingSizer( NULL );
552
553 delete item;
554 m_children.Erase( node );
555 return true;
556 }
557
558 bool wxSizer::Detach( wxSizer *sizer )
559 {
560 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
561
562 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
563 while (node)
564 {
565 wxSizerItem *item = node->GetData();
566
567 if (item->GetSizer() == sizer)
568 {
569 item->DetachSizer();
570 delete item;
571 m_children.Erase( node );
572 return true;
573 }
574 node = node->GetNext();
575 }
576
577 return false;
578 }
579
580 bool wxSizer::Detach( wxWindow *window )
581 {
582 wxASSERT_MSG( window, _T("Detaching NULL window") );
583
584 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
585 while (node)
586 {
587 wxSizerItem *item = node->GetData();
588
589 if (item->GetWindow() == window)
590 {
591 item->GetWindow()->SetContainingSizer( NULL );
592 delete item;
593 m_children.Erase( node );
594 return true;
595 }
596 node = node->GetNext();
597 }
598
599 return false;
600 }
601
602 bool wxSizer::Detach( int index )
603 {
604 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
605 false,
606 _T("Detach index is out of range") );
607
608 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
609
610 wxCHECK_MSG( node, false, _T("Failed to find child node") );
611
612 wxSizerItem *item = node->GetData();
613
614 if ( item->IsSizer() )
615 item->DetachSizer();
616 else if ( item->IsWindow() )
617 item->GetWindow()->SetContainingSizer( NULL );
618
619 delete item;
620 m_children.Erase( node );
621 return true;
622 }
623
624 void wxSizer::Clear( bool delete_windows )
625 {
626 // First clear the ContainingSizer pointers
627 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
628 while (node)
629 {
630 wxSizerItem *item = node->GetData();
631
632 if (item->IsWindow())
633 item->GetWindow()->SetContainingSizer( NULL );
634 node = node->GetNext();
635 }
636
637 // Destroy the windows if needed
638 if (delete_windows)
639 DeleteWindows();
640
641 // Now empty the list
642 WX_CLEAR_LIST(wxSizerItemList, m_children);
643 }
644
645 void wxSizer::DeleteWindows()
646 {
647 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
648 while (node)
649 {
650 wxSizerItem *item = node->GetData();
651
652 item->DeleteWindows();
653 node = node->GetNext();
654 }
655 }
656
657 wxSize wxSizer::Fit( wxWindow *window )
658 {
659 wxSize size(window->IsTopLevel() ? FitSize(window)
660 : GetMinWindowSize(window));
661
662 window->SetSize( size );
663
664 return size;
665 }
666
667 void wxSizer::FitInside( wxWindow *window )
668 {
669 wxSize size;
670 if (window->IsTopLevel())
671 size = VirtualFitSize( window );
672 else
673 size = GetMinClientSize( window );
674
675 window->SetVirtualSize( size );
676 }
677
678 void wxSizer::Layout()
679 {
680 // (re)calculates minimums needed for each item and other preparations
681 // for layout
682 CalcMin();
683
684 // Applies the layout and repositions/resizes the items
685 RecalcSizes();
686 }
687
688 void wxSizer::SetSizeHints( wxWindow *window )
689 {
690 // Preserve the window's max size hints, but set the
691 // lower bound according to the sizer calculations.
692
693 wxSize size = Fit( window );
694
695 window->SetSizeHints( size.x,
696 size.y,
697 window->GetMaxWidth(),
698 window->GetMaxHeight() );
699 }
700
701 void wxSizer::SetVirtualSizeHints( wxWindow *window )
702 {
703 // Preserve the window's max size hints, but set the
704 // lower bound according to the sizer calculations.
705
706 FitInside( window );
707 wxSize size( window->GetVirtualSize() );
708 window->SetVirtualSizeHints( size.x,
709 size.y,
710 window->GetMaxWidth(),
711 window->GetMaxHeight() );
712 }
713
714 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
715 {
716 return window->GetMaxSize();
717 }
718
719 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
720 {
721 wxSize minSize( GetMinSize() );
722 wxSize size( window->GetSize() );
723 wxSize client_size( window->GetClientSize() );
724
725 return wxSize( minSize.x+size.x-client_size.x,
726 minSize.y+size.y-client_size.y );
727 }
728
729 // TODO on mac we need a function that determines how much free space this
730 // min size contains, in order to make sure that we have 20 pixels of free
731 // space around the controls
732
733 // Return a window size that will fit within the screens dimensions
734 wxSize wxSizer::FitSize( wxWindow *window )
735 {
736 if ( window->IsTopLevel() )
737 {
738 wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
739 if ( tlw && tlw->IsAlwaysMaximized() )
740 {
741 return tlw->GetClientSize();
742 }
743 }
744
745 wxSize size = GetMinWindowSize( window );
746 wxSize sizeMax = GetMaxWindowSize( window );
747
748 // Limit the size if sizeMax != wxDefaultSize
749
750 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
751 size.x = sizeMax.x;
752 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
753 size.y = sizeMax.y;
754
755 return size;
756 }
757
758 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
759 {
760 wxSize maxSize( window->GetMaxSize() );
761
762 if ( maxSize != wxDefaultSize )
763 {
764 wxSize size( window->GetSize() );
765 wxSize client_size( window->GetClientSize() );
766
767 return wxSize( maxSize.x + client_size.x - size.x,
768 maxSize.y + client_size.y - size.y );
769 }
770 else
771 return wxDefaultSize;
772 }
773
774 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
775 {
776 return GetMinSize(); // Already returns client size.
777 }
778
779 wxSize wxSizer::VirtualFitSize( wxWindow *window )
780 {
781 wxSize size = GetMinClientSize( window );
782 wxSize sizeMax = GetMaxClientSize( window );
783
784 // Limit the size if sizeMax != wxDefaultSize
785
786 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
787 size.x = sizeMax.x;
788 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
789 size.y = sizeMax.y;
790
791 return size;
792 }
793
794 void wxSizer::SetDimension( int x, int y, int width, int height )
795 {
796 m_position.x = x;
797 m_position.y = y;
798 m_size.x = width;
799 m_size.y = height;
800 Layout();
801 }
802
803 wxSize wxSizer::GetMinSize()
804 {
805 wxSize ret( CalcMin() );
806 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
807 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
808 return ret;
809 }
810
811 void wxSizer::DoSetMinSize( int width, int height )
812 {
813 m_minSize.x = width;
814 m_minSize.y = height;
815 }
816
817 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
818 {
819 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
820
821 // Is it our immediate child?
822
823 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
824 while (node)
825 {
826 wxSizerItem *item = node->GetData();
827
828 if (item->GetWindow() == window)
829 {
830 item->SetMinSize( width, height );
831 return true;
832 }
833 node = node->GetNext();
834 }
835
836 // No? Search any subsizers we own then
837
838 node = m_children.GetFirst();
839 while (node)
840 {
841 wxSizerItem *item = node->GetData();
842
843 if ( item->GetSizer() &&
844 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
845 {
846 // A child sizer found the requested windw, exit.
847 return true;
848 }
849 node = node->GetNext();
850 }
851
852 return false;
853 }
854
855 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
856 {
857 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
858
859 // Is it our immediate child?
860
861 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
862 while (node)
863 {
864 wxSizerItem *item = node->GetData();
865
866 if (item->GetSizer() == sizer)
867 {
868 item->GetSizer()->DoSetMinSize( width, height );
869 return true;
870 }
871 node = node->GetNext();
872 }
873
874 // No? Search any subsizers we own then
875
876 node = m_children.GetFirst();
877 while (node)
878 {
879 wxSizerItem *item = node->GetData();
880
881 if ( item->GetSizer() &&
882 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
883 {
884 // A child found the requested sizer, exit.
885 return true;
886 }
887 node = node->GetNext();
888 }
889
890 return false;
891 }
892
893 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
894 {
895 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
896
897 wxCHECK_MSG( node, false, _T("Failed to find child node") );
898
899 wxSizerItem *item = node->GetData();
900
901 if (item->GetSizer())
902 {
903 // Sizers contains the minimal size in them, if not calculated ...
904 item->GetSizer()->DoSetMinSize( width, height );
905 }
906 else
907 {
908 // ... but the minimal size of spacers and windows is stored via the item
909 item->SetMinSize( width, height );
910 }
911
912 return true;
913 }
914
915 wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
916 {
917 wxASSERT_MSG( window, _T("GetItem for NULL window") );
918
919 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
920 while (node)
921 {
922 wxSizerItem *item = node->GetData();
923
924 if (item->GetWindow() == window)
925 {
926 return item;
927 }
928 else if (recursive && item->IsSizer())
929 {
930 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
931 if (subitem)
932 return subitem;
933 }
934
935 node = node->GetNext();
936 }
937
938 return NULL;
939 }
940
941 wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
942 {
943 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
944
945 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
946 while (node)
947 {
948 wxSizerItem *item = node->GetData();
949
950 if (item->GetSizer() == sizer)
951 {
952 return item;
953 }
954 else if (recursive && item->IsSizer())
955 {
956 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
957 if (subitem)
958 return subitem;
959 }
960
961 node = node->GetNext();
962 }
963
964 return NULL;
965 }
966
967 wxSizerItem* wxSizer::GetItem( size_t index )
968 {
969 wxCHECK_MSG( index < m_children.GetCount(),
970 NULL,
971 _T("GetItem index is out of range") );
972
973 return m_children.Item( index )->GetData();
974 }
975
976 bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
977 {
978 wxSizerItem *item = GetItem( window, recursive );
979
980 if ( item )
981 {
982 item->Show( show );
983 return true;
984 }
985
986 return false;
987 }
988
989 bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
990 {
991 wxSizerItem *item = GetItem( sizer, recursive );
992
993 if ( item )
994 {
995 item->Show( show );
996 return true;
997 }
998
999 return false;
1000 }
1001
1002 bool wxSizer::Show( size_t index, bool show)
1003 {
1004 wxSizerItem *item = GetItem( index );
1005
1006 if ( item )
1007 {
1008 item->Show( show );
1009 return true;
1010 }
1011
1012 return false;
1013 }
1014
1015 void wxSizer::ShowItems( bool show )
1016 {
1017 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1018 while (node)
1019 {
1020 node->GetData()->Show( show );
1021 node = node->GetNext();
1022 }
1023 }
1024
1025 bool wxSizer::IsShown( wxWindow *window ) const
1026 {
1027 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1028 while (node)
1029 {
1030 wxSizerItem *item = node->GetData();
1031
1032 if (item->GetWindow() == window)
1033 {
1034 return item->IsShown();
1035 }
1036 node = node->GetNext();
1037 }
1038
1039 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1040
1041 return false;
1042 }
1043
1044 bool wxSizer::IsShown( wxSizer *sizer ) const
1045 {
1046 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1047 while (node)
1048 {
1049 wxSizerItem *item = node->GetData();
1050
1051 if (item->GetSizer() == sizer)
1052 {
1053 return item->IsShown();
1054 }
1055 node = node->GetNext();
1056 }
1057
1058 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1059
1060 return false;
1061 }
1062
1063 bool wxSizer::IsShown( size_t index ) const
1064 {
1065 wxCHECK_MSG( index < m_children.GetCount(),
1066 false,
1067 _T("IsShown index is out of range") );
1068
1069 return m_children.Item( index )->GetData()->IsShown();
1070 }
1071
1072
1073 //---------------------------------------------------------------------------
1074 // wxGridSizer
1075 //---------------------------------------------------------------------------
1076
1077 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
1078 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
1079 , m_cols( cols )
1080 , m_vgap( vgap )
1081 , m_hgap( hgap )
1082 {
1083 }
1084
1085 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
1086 : m_rows( cols == 0 ? 1 : 0 )
1087 , m_cols( cols )
1088 , m_vgap( vgap )
1089 , m_hgap( hgap )
1090 {
1091 }
1092
1093 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
1094 {
1095 int nitems = m_children.GetCount();
1096 if ( nitems)
1097 {
1098 if ( m_cols )
1099 {
1100 ncols = m_cols;
1101 nrows = (nitems + m_cols - 1) / m_cols;
1102 }
1103 else if ( m_rows )
1104 {
1105 ncols = (nitems + m_rows - 1) / m_rows;
1106 nrows = m_rows;
1107 }
1108 else // 0 columns, 0 rows?
1109 {
1110 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
1111
1112 nrows = ncols = 0;
1113 }
1114 }
1115
1116 return nitems;
1117 }
1118
1119 void wxGridSizer::RecalcSizes()
1120 {
1121 int nitems, nrows, ncols;
1122 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1123 return;
1124
1125 wxSize sz( GetSize() );
1126 wxPoint pt( GetPosition() );
1127
1128 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1129 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
1130
1131 int x = pt.x;
1132 for (int c = 0; c < ncols; c++)
1133 {
1134 int y = pt.y;
1135 for (int r = 0; r < nrows; r++)
1136 {
1137 int i = r * ncols + c;
1138 if (i < nitems)
1139 {
1140 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1141
1142 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
1143
1144 SetItemBounds( node->GetData(), x, y, w, h);
1145 }
1146 y = y + h + m_vgap;
1147 }
1148 x = x + w + m_hgap;
1149 }
1150 }
1151
1152 wxSize wxGridSizer::CalcMin()
1153 {
1154 int nrows, ncols;
1155 if ( CalcRowsCols(nrows, ncols) == 0 )
1156 return wxSize(10, 10);
1157
1158 // Find the max width and height for any component
1159 int w = 0;
1160 int h = 0;
1161
1162 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1163 while (node)
1164 {
1165 wxSizerItem *item = node->GetData();
1166 wxSize sz( item->CalcMin() );
1167
1168 w = wxMax( w, sz.x );
1169 h = wxMax( h, sz.y );
1170
1171 node = node->GetNext();
1172 }
1173
1174 return wxSize( ncols * w + (ncols-1) * m_hgap,
1175 nrows * h + (nrows-1) * m_vgap );
1176 }
1177
1178 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1179 {
1180 wxPoint pt( x,y );
1181 wxSize sz( item->GetMinSizeWithBorder() );
1182 int flag = item->GetFlag();
1183
1184 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1185 {
1186 sz = wxSize(w, h);
1187 }
1188 else
1189 {
1190 if (flag & wxALIGN_CENTER_HORIZONTAL)
1191 {
1192 pt.x = x + (w - sz.x) / 2;
1193 }
1194 else if (flag & wxALIGN_RIGHT)
1195 {
1196 pt.x = x + (w - sz.x);
1197 }
1198
1199 if (flag & wxALIGN_CENTER_VERTICAL)
1200 {
1201 pt.y = y + (h - sz.y) / 2;
1202 }
1203 else if (flag & wxALIGN_BOTTOM)
1204 {
1205 pt.y = y + (h - sz.y);
1206 }
1207 }
1208
1209 item->SetDimension(pt, sz);
1210 }
1211
1212 //---------------------------------------------------------------------------
1213 // wxFlexGridSizer
1214 //---------------------------------------------------------------------------
1215
1216 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1217 : wxGridSizer( rows, cols, vgap, hgap ),
1218 m_flexDirection(wxBOTH),
1219 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1220 {
1221 }
1222
1223 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1224 : wxGridSizer( cols, vgap, hgap ),
1225 m_flexDirection(wxBOTH),
1226 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1227 {
1228 }
1229
1230 wxFlexGridSizer::~wxFlexGridSizer()
1231 {
1232 }
1233
1234 void wxFlexGridSizer::RecalcSizes()
1235 {
1236 int nitems, nrows, ncols;
1237 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1238 return;
1239
1240 wxPoint pt( GetPosition() );
1241 wxSize sz( GetSize() );
1242
1243 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
1244
1245 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1246
1247 int x = pt.x;
1248 for (int c = 0; c < ncols; c++)
1249 {
1250 int y = pt.y;
1251 for (int r = 0; r < nrows; r++)
1252 {
1253 int i = r * ncols + c;
1254 if (i < nitems)
1255 {
1256 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1257
1258 wxASSERT_MSG( node, _T("Failed to find node") );
1259
1260 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1261 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1262
1263 SetItemBounds( node->GetData(), x, y, w, h);
1264 }
1265 if (m_rowHeights[r] != -1)
1266 y = y + m_rowHeights[r] + m_vgap;
1267 }
1268 if (m_colWidths[c] != -1)
1269 x = x + m_colWidths[c] + m_hgap;
1270 }
1271 }
1272
1273 wxSize wxFlexGridSizer::CalcMin()
1274 {
1275 int nrows,
1276 ncols;
1277 size_t i, s;
1278
1279 // Number of rows/columns can change as items are added or removed.
1280 if ( !CalcRowsCols(nrows, ncols) )
1281 return wxSize(10, 10);
1282
1283 m_rowHeights.SetCount(nrows);
1284 m_colWidths.SetCount(ncols);
1285
1286 // We have to recalcuate the sizes in case the item minimum size has
1287 // changed since the previous layout, or the item has been hidden using
1288 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1289 // dimension of the row/column will be -1, indicating that the column
1290 // itself is hidden.
1291 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1292 m_rowHeights[ i ] = -1;
1293 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1294 m_colWidths[ i ] = -1;
1295
1296 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1297
1298 i = 0;
1299 while (node)
1300 {
1301 wxSizerItem *item = node->GetData();
1302 if ( item->IsShown() )
1303 {
1304 wxSize sz( item->CalcMin() );
1305 int row = i / ncols;
1306 int col = i % ncols;
1307
1308 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1309 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1310 }
1311
1312 node = node->GetNext();
1313 i++;
1314 }
1315
1316 AdjustForFlexDirection();
1317
1318 // Sum total minimum size, including gaps between rows/columns.
1319 // -1 is used as a magic number meaning empty column.
1320 int width = 0;
1321 for (int col = 0; col < ncols; col++)
1322 if ( m_colWidths[ col ] != -1 )
1323 width += m_colWidths[ col ] + m_hgap;
1324 if (width > 0)
1325 width -= m_hgap;
1326
1327 int height = 0;
1328 for (int row = 0; row < nrows; row++)
1329 if ( m_rowHeights[ row ] != -1 )
1330 height += m_rowHeights[ row ] + m_vgap;
1331 if (height > 0)
1332 height -= m_vgap;
1333
1334 m_calculatedMinSize = wxSize( width, height );
1335 return m_calculatedMinSize;
1336 }
1337
1338 void wxFlexGridSizer::AdjustForFlexDirection()
1339 {
1340 // the logic in CalcMin works when we resize flexibly in both directions
1341 // but maybe this is not the case
1342 if ( m_flexDirection != wxBOTH )
1343 {
1344 // select the array corresponding to the direction in which we do *not*
1345 // resize flexibly
1346 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1347 : m_rowHeights;
1348
1349 const size_t count = array.GetCount();
1350
1351 // find the largest value in this array
1352 size_t n;
1353 int largest = 0;
1354
1355 for ( n = 0; n < count; ++n )
1356 {
1357 if ( array[n] > largest )
1358 largest = array[n];
1359 }
1360
1361 // and now fill it with the largest value
1362 for ( n = 0; n < count; ++n )
1363 {
1364 array[n] = largest;
1365 }
1366 }
1367 }
1368
1369
1370 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1371 int nrows, int ncols)
1372 {
1373 // what to do with the rows? by default, resize them proportionally
1374 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1375 {
1376 int sum_proportions = 0;
1377 int growable_space = 0;
1378 int num = 0;
1379 size_t idx;
1380 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1381 {
1382 // Since the number of rows/columns can change as items are
1383 // inserted/deleted, we need to verify at runtime that the
1384 // requested growable rows/columns are still valid.
1385 if (m_growableRows[idx] >= nrows)
1386 continue;
1387
1388 // If all items in a row/column are hidden, that row/column will
1389 // have a dimension of -1. This causes the row/column to be
1390 // hidden completely.
1391 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1392 continue;
1393 sum_proportions += m_growableRowsProportions[idx];
1394 growable_space += m_rowHeights[ m_growableRows[idx] ];
1395 num++;
1396 }
1397
1398 if (num > 0)
1399 {
1400 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1401 {
1402 if (m_growableRows[idx] >= nrows )
1403 continue;
1404 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1405 m_rowHeights[ m_growableRows[idx] ] = 0;
1406 else
1407 {
1408 int delta = (sz.y - minsz.y);
1409 if (sum_proportions == 0)
1410 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1411 else
1412 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1413 m_rowHeights[ m_growableRows[idx] ] = delta;
1414 }
1415 }
1416 }
1417 }
1418 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1419 {
1420 // rounding problem?
1421 for ( int row = 0; row < nrows; ++row )
1422 m_rowHeights[ row ] = sz.y / nrows;
1423 }
1424
1425 // the same logic as above but for the columns
1426 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1427 {
1428 int sum_proportions = 0;
1429 int growable_space = 0;
1430 int num = 0;
1431 size_t idx;
1432 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1433 {
1434 // Since the number of rows/columns can change as items are
1435 // inserted/deleted, we need to verify at runtime that the
1436 // requested growable rows/columns are still valid.
1437 if (m_growableCols[idx] >= ncols)
1438 continue;
1439
1440 // If all items in a row/column are hidden, that row/column will
1441 // have a dimension of -1. This causes the column to be hidden
1442 // completely.
1443 if (m_colWidths[ m_growableCols[idx] ] == -1)
1444 continue;
1445 sum_proportions += m_growableColsProportions[idx];
1446 growable_space += m_colWidths[ m_growableCols[idx] ];
1447 num++;
1448 }
1449
1450 if (num > 0)
1451 {
1452 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1453 {
1454 if (m_growableCols[idx] >= ncols )
1455 continue;
1456 if (m_colWidths[ m_growableCols[idx] ] == -1)
1457 m_colWidths[ m_growableCols[idx] ] = 0;
1458 else
1459 {
1460 int delta = (sz.x - minsz.x);
1461 if (sum_proportions == 0)
1462 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1463 else
1464 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1465 m_colWidths[ m_growableCols[idx] ] = delta;
1466 }
1467 }
1468 }
1469 }
1470 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1471 {
1472 for ( int col=0; col < ncols; ++col )
1473 m_colWidths[ col ] = sz.x / ncols;
1474 }
1475 }
1476
1477
1478 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1479 {
1480 m_growableRows.Add( idx );
1481 m_growableRowsProportions.Add( proportion );
1482 }
1483
1484 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1485 {
1486 m_growableCols.Add( idx );
1487 m_growableColsProportions.Add( proportion );
1488 }
1489
1490 // helper function for RemoveGrowableCol/Row()
1491 static void
1492 DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1493 {
1494 const size_t count = items.size();
1495 for ( size_t n = 0; n < count; n++ )
1496 {
1497 if ( (size_t)items[n] == idx )
1498 {
1499 items.RemoveAt(n);
1500 proportions.RemoveAt(n);
1501 return;
1502 }
1503 }
1504
1505 wxFAIL_MSG( _T("column/row is already not growable") );
1506 }
1507
1508 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1509 {
1510 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1511 }
1512
1513 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1514 {
1515 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
1516 }
1517
1518 //---------------------------------------------------------------------------
1519 // wxBoxSizer
1520 //---------------------------------------------------------------------------
1521
1522 wxBoxSizer::wxBoxSizer( int orient )
1523 : m_orient( orient )
1524 {
1525 }
1526
1527 void wxBoxSizer::RecalcSizes()
1528 {
1529 if (m_children.GetCount() == 0)
1530 return;
1531
1532 int delta = 0;
1533 if (m_stretchable)
1534 {
1535 if (m_orient == wxHORIZONTAL)
1536 delta = m_size.x - m_fixedWidth;
1537 else
1538 delta = m_size.y - m_fixedHeight;
1539 }
1540
1541 wxPoint pt( m_position );
1542
1543 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1544 while (node)
1545 {
1546 wxSizerItem *item = node->GetData();
1547
1548 if (item->IsShown())
1549 {
1550 wxSize size( item->GetMinSizeWithBorder() );
1551
1552 if (m_orient == wxVERTICAL)
1553 {
1554 wxCoord height = size.y;
1555 if (item->GetProportion())
1556 {
1557 // Because of at least one visible item has non-zero
1558 // proportion then m_stretchable is not zero
1559 height = (delta * item->GetProportion()) / m_stretchable;
1560 }
1561
1562 wxPoint child_pos( pt );
1563 wxSize child_size( size.x, height );
1564
1565 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1566 child_size.x = m_size.x;
1567 else if (item->GetFlag() & wxALIGN_RIGHT)
1568 child_pos.x += m_size.x - size.x;
1569 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1570 // XXX wxCENTER is added for backward compatibility;
1571 // wxALIGN_CENTER should be used in new code
1572 child_pos.x += (m_size.x - size.x) / 2;
1573
1574 item->SetDimension( child_pos, child_size );
1575
1576 pt.y += height;
1577 }
1578 else
1579 {
1580 wxCoord width = size.x;
1581 if (item->GetProportion())
1582 {
1583 // Because of at least one visible item has non-zero
1584 // proportion then m_stretchable is not zero
1585 width = (delta * item->GetProportion()) / m_stretchable;
1586 }
1587
1588 wxPoint child_pos( pt );
1589 wxSize child_size( width, size.y );
1590
1591 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1592 child_size.y = m_size.y;
1593 else if (item->GetFlag() & wxALIGN_BOTTOM)
1594 child_pos.y += m_size.y - size.y;
1595 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1596 // XXX wxCENTER is added for backward compatibility;
1597 // wxALIGN_CENTER should be used in new code
1598 child_pos.y += (m_size.y - size.y) / 2;
1599
1600 item->SetDimension( child_pos, child_size );
1601
1602 pt.x += width;
1603 }
1604 }
1605
1606 node = node->GetNext();
1607 }
1608 }
1609
1610 wxSize wxBoxSizer::CalcMin()
1611 {
1612 if (m_children.GetCount() == 0)
1613 return wxSize(10,10);
1614
1615 m_stretchable = 0;
1616 m_minWidth = 0;
1617 m_minHeight = 0;
1618 m_fixedWidth = 0;
1619 m_fixedHeight = 0;
1620
1621 // precalc item minsizes and count proportions
1622 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1623 while (node)
1624 {
1625 wxSizerItem *item = node->GetData();
1626
1627 if ( item->IsShown() )
1628 {
1629 item->CalcMin(); // result is stored in the item
1630
1631 m_stretchable += item->GetProportion();
1632 }
1633
1634 node = node->GetNext();
1635 }
1636
1637 // Total minimum size (width or height) of sizer
1638 int maxMinSize = 0;
1639
1640 node = m_children.GetFirst();
1641 while (node)
1642 {
1643 wxSizerItem *item = node->GetData();
1644
1645 if (item->IsShown() && item->GetProportion() != 0)
1646 {
1647 int stretch = item->GetProportion();
1648 wxSize size( item->GetMinSizeWithBorder() );
1649 int minSize;
1650
1651 // Integer division rounded up is (a + b - 1) / b
1652 // Round up needed in order to guarantee that all
1653 // all items will have size not less then their min size
1654 if (m_orient == wxHORIZONTAL)
1655 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1656 else
1657 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1658
1659 if (minSize > maxMinSize)
1660 maxMinSize = minSize;
1661 }
1662 node = node->GetNext();
1663 }
1664
1665 // Calculate overall minimum size
1666 node = m_children.GetFirst();
1667 while (node)
1668 {
1669 wxSizerItem *item = node->GetData();
1670
1671 if (item->IsShown())
1672 {
1673 wxSize size( item->GetMinSizeWithBorder() );
1674 if (item->GetProportion() != 0)
1675 {
1676 if (m_orient == wxHORIZONTAL)
1677 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1678 else
1679 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1680 }
1681 else
1682 {
1683 if (m_orient == wxVERTICAL)
1684 {
1685 m_fixedHeight += size.y;
1686 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1687 }
1688 else
1689 {
1690 m_fixedWidth += size.x;
1691 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1692 }
1693 }
1694
1695 if (m_orient == wxHORIZONTAL)
1696 {
1697 m_minWidth += size.x;
1698 m_minHeight = wxMax( m_minHeight, size.y );
1699 }
1700 else
1701 {
1702 m_minHeight += size.y;
1703 m_minWidth = wxMax( m_minWidth, size.x );
1704 }
1705 }
1706 node = node->GetNext();
1707 }
1708
1709 return wxSize( m_minWidth, m_minHeight );
1710 }
1711
1712 //---------------------------------------------------------------------------
1713 // wxStaticBoxSizer
1714 //---------------------------------------------------------------------------
1715
1716 #if wxUSE_STATBOX
1717
1718 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1719 : wxBoxSizer( orient ),
1720 m_staticBox( box )
1721 {
1722 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1723
1724 // do this so that our Detach() is called if the static box is destroyed
1725 // before we are
1726 m_staticBox->SetContainingSizer(this);
1727 }
1728
1729 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1730 : wxBoxSizer(orient),
1731 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1732 {
1733 // same as above
1734 m_staticBox->SetContainingSizer(this);
1735 }
1736
1737 wxStaticBoxSizer::~wxStaticBoxSizer()
1738 {
1739 delete m_staticBox;
1740 }
1741
1742 static void GetStaticBoxBorders( wxStaticBox *box,
1743 int *borderTop,
1744 int *borderOther)
1745 {
1746 // this has to be done platform by platform as there is no way to
1747 // guess the thickness of a wxStaticBox border
1748 box->GetBordersForSizer(borderTop, borderOther);
1749 }
1750
1751 void wxStaticBoxSizer::RecalcSizes()
1752 {
1753 int top_border, other_border;
1754 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1755
1756 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1757
1758 wxPoint old_pos( m_position );
1759 m_position.x += other_border;
1760 m_position.y += top_border;
1761 wxSize old_size( m_size );
1762 m_size.x -= 2*other_border;
1763 m_size.y -= top_border + other_border;
1764
1765 wxBoxSizer::RecalcSizes();
1766
1767 m_position = old_pos;
1768 m_size = old_size;
1769 }
1770
1771 wxSize wxStaticBoxSizer::CalcMin()
1772 {
1773 int top_border, other_border;
1774 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1775
1776 wxSize ret( wxBoxSizer::CalcMin() );
1777 ret.x += 2*other_border;
1778 ret.y += other_border + top_border;
1779
1780 return ret;
1781 }
1782
1783 void wxStaticBoxSizer::ShowItems( bool show )
1784 {
1785 m_staticBox->Show( show );
1786 wxBoxSizer::ShowItems( show );
1787 }
1788
1789 bool wxStaticBoxSizer::Detach( wxWindow *window )
1790 {
1791 // avoid deleting m_staticBox in our dtor if it's being detached from the
1792 // sizer (which can happen because it's being already destroyed for
1793 // example)
1794 if ( window == m_staticBox )
1795 {
1796 m_staticBox = NULL;
1797 return true;
1798 }
1799
1800 return wxSizer::Detach( window );
1801 }
1802
1803 #endif // wxUSE_STATBOX
1804
1805 #if wxUSE_BUTTON
1806
1807 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1808 : wxBoxSizer(wxHORIZONTAL)
1809 {
1810 // Vertical buttons with lots of space on either side
1811 // looks rubbish on WinCE, so let's not do this for now.
1812 // If we are going to use vertical buttons, we should
1813 // put the sizer to the right of other controls in the dialog,
1814 // and that's beyond the scope of this sizer.
1815 #ifndef __WXWINCE__
1816 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1817 // If we have a PDA screen, put yes/no button over
1818 // all other buttons, otherwise on the left side.
1819 if (is_pda)
1820 m_orient = wxVERTICAL;
1821 #endif
1822
1823 m_buttonAffirmative = NULL;
1824 m_buttonApply = NULL;
1825 m_buttonNegative = NULL;
1826 m_buttonCancel = NULL;
1827 m_buttonHelp = NULL;
1828 }
1829
1830 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1831 {
1832 switch (mybutton->GetId())
1833 {
1834 case wxID_OK:
1835 case wxID_YES:
1836 case wxID_SAVE:
1837 m_buttonAffirmative = mybutton;
1838 break;
1839 case wxID_APPLY:
1840 m_buttonApply = mybutton;
1841 break;
1842 case wxID_NO:
1843 m_buttonNegative = mybutton;
1844 break;
1845 case wxID_CANCEL:
1846 m_buttonCancel = mybutton;
1847 break;
1848 case wxID_HELP:
1849 case wxID_CONTEXT_HELP:
1850 m_buttonHelp = mybutton;
1851 break;
1852 default:
1853 break;
1854 }
1855 }
1856
1857 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1858 {
1859 m_buttonAffirmative = button;
1860 }
1861
1862 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1863 {
1864 m_buttonNegative = button;
1865 }
1866
1867 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1868 {
1869 m_buttonCancel = button;
1870 }
1871
1872 void wxStdDialogButtonSizer::Realize()
1873 {
1874 #ifdef __WXMAC__
1875 Add(0, 0, 0, wxLEFT, 6);
1876 if (m_buttonHelp)
1877 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1878
1879 if (m_buttonNegative){
1880 // HIG POLICE BULLETIN - destructive buttons need extra padding
1881 // 24 pixels on either side
1882 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1883 }
1884
1885 // extra whitespace between help/negative and cancel/ok buttons
1886 Add(0, 0, 1, wxEXPAND, 0);
1887
1888 if (m_buttonCancel){
1889 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1890 // Cancel or help should be default
1891 // m_buttonCancel->SetDefaultButton();
1892 }
1893
1894 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1895 // figure the best place is between Cancel and OK
1896 if (m_buttonApply)
1897 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1898
1899 if (m_buttonAffirmative){
1900 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1901
1902 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1903 // these buttons have set labels under Mac so we should use them
1904 m_buttonAffirmative->SetLabel(_("Save"));
1905 m_buttonNegative->SetLabel(_("Don't Save"));
1906 }
1907 }
1908
1909 // Extra space around and at the right
1910 Add(12, 24);
1911 #elif defined(__WXGTK20__)
1912 Add(0, 0, 0, wxLEFT, 9);
1913 if (m_buttonHelp)
1914 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1915
1916 // extra whitespace between help and cancel/ok buttons
1917 Add(0, 0, 1, wxEXPAND, 0);
1918
1919 if (m_buttonNegative){
1920 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1921 }
1922
1923 if (m_buttonCancel){
1924 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1925 // Cancel or help should be default
1926 // m_buttonCancel->SetDefaultButton();
1927 }
1928
1929 if (m_buttonApply)
1930 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1931
1932 if (m_buttonAffirmative)
1933 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1934 #elif defined(__WXMSW__)
1935 // Windows
1936
1937 // right-justify buttons
1938 Add(0, 0, 1, wxEXPAND, 0);
1939
1940 if (m_buttonAffirmative){
1941 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
1942 }
1943
1944 if (m_buttonNegative){
1945 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
1946 }
1947
1948 if (m_buttonCancel){
1949 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
1950 }
1951 if (m_buttonApply)
1952 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
1953
1954 if (m_buttonHelp)
1955 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
1956 #else
1957 // GTK+1 and any other platform
1958
1959 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
1960 if (m_buttonHelp)
1961 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1962
1963 // extra whitespace between help and cancel/ok buttons
1964 Add(0, 0, 1, wxEXPAND, 0);
1965
1966 if (m_buttonApply)
1967 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1968
1969 if (m_buttonAffirmative){
1970 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1971 }
1972
1973 if (m_buttonNegative){
1974 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1975 }
1976
1977 if (m_buttonCancel){
1978 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
1979 // Cancel or help should be default
1980 // m_buttonCancel->SetDefaultButton();
1981 }
1982
1983 #endif
1984 }
1985
1986 #endif // wxUSE_BUTTON
1987
1988 #if WXWIN_COMPATIBILITY_2_4
1989
1990 // ----------------------------------------------------------------------------
1991 // wxNotebookSizer
1992 // ----------------------------------------------------------------------------
1993
1994 #if wxUSE_BOOKCTRL
1995 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1996 #if wxUSE_NOTEBOOK
1997 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1998 #endif // wxUSE_NOTEBOOK
1999 #endif // wxUSE_BOOKCTRL
2000
2001 #if wxUSE_BOOKCTRL
2002
2003 #if WXWIN_COMPATIBILITY_2_6
2004
2005 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
2006 : m_bookctrl(bookctrl)
2007 {
2008 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
2009 }
2010
2011 #endif // WXWIN_COMPATIBILITY_2_6
2012
2013 void wxBookCtrlSizer::RecalcSizes()
2014 {
2015 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
2016 }
2017
2018 wxSize wxBookCtrlSizer::CalcMin()
2019 {
2020 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
2021
2022 sizeBorder.x += 5;
2023 sizeBorder.y += 5;
2024
2025 if ( m_bookctrl->GetPageCount() == 0 )
2026 {
2027 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
2028 }
2029
2030 int maxX = 0;
2031 int maxY = 0;
2032
2033 wxWindowList::compatibility_iterator
2034 node = m_bookctrl->GetChildren().GetFirst();
2035 while (node)
2036 {
2037 wxWindow *item = node->GetData();
2038 wxSizer *itemsizer = item->GetSizer();
2039
2040 if (itemsizer)
2041 {
2042 wxSize subsize( itemsizer->CalcMin() );
2043
2044 if (subsize.x > maxX)
2045 maxX = subsize.x;
2046 if (subsize.y > maxY)
2047 maxY = subsize.y;
2048 }
2049
2050 node = node->GetNext();
2051 }
2052
2053 return wxSize( maxX, maxY ) + sizeBorder;
2054 }
2055
2056 #if wxUSE_NOTEBOOK
2057
2058 #if WXWIN_COMPATIBILITY_2_6
2059
2060 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
2061 {
2062 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
2063 m_bookctrl = nb;
2064 }
2065
2066 #endif // WXWIN_COMPATIBILITY_2_6
2067
2068 #endif // wxUSE_NOTEBOOOK
2069 #endif // wxUSE_BOOKCTRL
2070
2071 #endif // WXWIN_COMPATIBILITY_2_4