Include wx/choicdlg.h, wx/textdlg.h and wx/filedlg.h according to precompiled headers...
[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::RemoveGrowableRow( size_t idx )
1485 {
1486 m_growableRows.Remove( idx );
1487 }
1488
1489 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1490 {
1491 m_growableCols.Add( idx );
1492 m_growableColsProportions.Add( proportion );
1493 }
1494
1495 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1496 {
1497 m_growableCols.Remove( idx );
1498 }
1499
1500 //---------------------------------------------------------------------------
1501 // wxBoxSizer
1502 //---------------------------------------------------------------------------
1503
1504 wxBoxSizer::wxBoxSizer( int orient )
1505 : m_orient( orient )
1506 {
1507 }
1508
1509 void wxBoxSizer::RecalcSizes()
1510 {
1511 if (m_children.GetCount() == 0)
1512 return;
1513
1514 int delta = 0;
1515 if (m_stretchable)
1516 {
1517 if (m_orient == wxHORIZONTAL)
1518 delta = m_size.x - m_fixedWidth;
1519 else
1520 delta = m_size.y - m_fixedHeight;
1521 }
1522
1523 wxPoint pt( m_position );
1524
1525 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1526 while (node)
1527 {
1528 wxSizerItem *item = node->GetData();
1529
1530 if (item->IsShown())
1531 {
1532 wxSize size( item->GetMinSizeWithBorder() );
1533
1534 if (m_orient == wxVERTICAL)
1535 {
1536 wxCoord height = size.y;
1537 if (item->GetProportion())
1538 {
1539 // Because of at least one visible item has non-zero
1540 // proportion then m_stretchable is not zero
1541 height = (delta * item->GetProportion()) / m_stretchable;
1542 }
1543
1544 wxPoint child_pos( pt );
1545 wxSize child_size( size.x, height );
1546
1547 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1548 child_size.x = m_size.x;
1549 else if (item->GetFlag() & wxALIGN_RIGHT)
1550 child_pos.x += m_size.x - size.x;
1551 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1552 // XXX wxCENTER is added for backward compatibility;
1553 // wxALIGN_CENTER should be used in new code
1554 child_pos.x += (m_size.x - size.x) / 2;
1555
1556 item->SetDimension( child_pos, child_size );
1557
1558 pt.y += height;
1559 }
1560 else
1561 {
1562 wxCoord width = size.x;
1563 if (item->GetProportion())
1564 {
1565 // Because of at least one visible item has non-zero
1566 // proportion then m_stretchable is not zero
1567 width = (delta * item->GetProportion()) / m_stretchable;
1568 }
1569
1570 wxPoint child_pos( pt );
1571 wxSize child_size( width, size.y );
1572
1573 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1574 child_size.y = m_size.y;
1575 else if (item->GetFlag() & wxALIGN_BOTTOM)
1576 child_pos.y += m_size.y - size.y;
1577 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1578 // XXX wxCENTER is added for backward compatibility;
1579 // wxALIGN_CENTER should be used in new code
1580 child_pos.y += (m_size.y - size.y) / 2;
1581
1582 item->SetDimension( child_pos, child_size );
1583
1584 pt.x += width;
1585 }
1586 }
1587
1588 node = node->GetNext();
1589 }
1590 }
1591
1592 wxSize wxBoxSizer::CalcMin()
1593 {
1594 if (m_children.GetCount() == 0)
1595 return wxSize(10,10);
1596
1597 m_stretchable = 0;
1598 m_minWidth = 0;
1599 m_minHeight = 0;
1600 m_fixedWidth = 0;
1601 m_fixedHeight = 0;
1602
1603 // precalc item minsizes and count proportions
1604 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1605 while (node)
1606 {
1607 wxSizerItem *item = node->GetData();
1608
1609 if ( item->IsShown() )
1610 {
1611 item->CalcMin(); // result is stored in the item
1612
1613 m_stretchable += item->GetProportion();
1614 }
1615
1616 node = node->GetNext();
1617 }
1618
1619 // Total minimum size (width or height) of sizer
1620 int maxMinSize = 0;
1621
1622 node = m_children.GetFirst();
1623 while (node)
1624 {
1625 wxSizerItem *item = node->GetData();
1626
1627 if (item->IsShown() && item->GetProportion() != 0)
1628 {
1629 int stretch = item->GetProportion();
1630 wxSize size( item->GetMinSizeWithBorder() );
1631 int minSize;
1632
1633 // Integer division rounded up is (a + b - 1) / b
1634 // Round up needed in order to guarantee that all
1635 // all items will have size not less then their min size
1636 if (m_orient == wxHORIZONTAL)
1637 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1638 else
1639 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1640
1641 if (minSize > maxMinSize)
1642 maxMinSize = minSize;
1643 }
1644 node = node->GetNext();
1645 }
1646
1647 // Calculate overall minimum size
1648 node = m_children.GetFirst();
1649 while (node)
1650 {
1651 wxSizerItem *item = node->GetData();
1652
1653 if (item->IsShown())
1654 {
1655 wxSize size( item->GetMinSizeWithBorder() );
1656 if (item->GetProportion() != 0)
1657 {
1658 if (m_orient == wxHORIZONTAL)
1659 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1660 else
1661 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1662 }
1663 else
1664 {
1665 if (m_orient == wxVERTICAL)
1666 {
1667 m_fixedHeight += size.y;
1668 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1669 }
1670 else
1671 {
1672 m_fixedWidth += size.x;
1673 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1674 }
1675 }
1676
1677 if (m_orient == wxHORIZONTAL)
1678 {
1679 m_minWidth += size.x;
1680 m_minHeight = wxMax( m_minHeight, size.y );
1681 }
1682 else
1683 {
1684 m_minHeight += size.y;
1685 m_minWidth = wxMax( m_minWidth, size.x );
1686 }
1687 }
1688 node = node->GetNext();
1689 }
1690
1691 return wxSize( m_minWidth, m_minHeight );
1692 }
1693
1694 //---------------------------------------------------------------------------
1695 // wxStaticBoxSizer
1696 //---------------------------------------------------------------------------
1697
1698 #if wxUSE_STATBOX
1699
1700 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1701 : wxBoxSizer( orient ),
1702 m_staticBox( box )
1703 {
1704 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1705
1706 // do this so that our Detach() is called if the static box is destroyed
1707 // before we are
1708 m_staticBox->SetContainingSizer(this);
1709 }
1710
1711 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1712 : wxBoxSizer(orient),
1713 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1714 {
1715 // same as above
1716 m_staticBox->SetContainingSizer(this);
1717 }
1718
1719 wxStaticBoxSizer::~wxStaticBoxSizer()
1720 {
1721 delete m_staticBox;
1722 }
1723
1724 static void GetStaticBoxBorders( wxStaticBox *box,
1725 int *borderTop,
1726 int *borderOther)
1727 {
1728 // this has to be done platform by platform as there is no way to
1729 // guess the thickness of a wxStaticBox border
1730 box->GetBordersForSizer(borderTop, borderOther);
1731 }
1732
1733 void wxStaticBoxSizer::RecalcSizes()
1734 {
1735 int top_border, other_border;
1736 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1737
1738 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1739
1740 wxPoint old_pos( m_position );
1741 m_position.x += other_border;
1742 m_position.y += top_border;
1743 wxSize old_size( m_size );
1744 m_size.x -= 2*other_border;
1745 m_size.y -= top_border + other_border;
1746
1747 wxBoxSizer::RecalcSizes();
1748
1749 m_position = old_pos;
1750 m_size = old_size;
1751 }
1752
1753 wxSize wxStaticBoxSizer::CalcMin()
1754 {
1755 int top_border, other_border;
1756 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1757
1758 wxSize ret( wxBoxSizer::CalcMin() );
1759 ret.x += 2*other_border;
1760 ret.y += other_border + top_border;
1761
1762 return ret;
1763 }
1764
1765 void wxStaticBoxSizer::ShowItems( bool show )
1766 {
1767 m_staticBox->Show( show );
1768 wxBoxSizer::ShowItems( show );
1769 }
1770
1771 bool wxStaticBoxSizer::Detach( wxWindow *window )
1772 {
1773 // avoid deleting m_staticBox in our dtor if it's being detached from the
1774 // sizer (which can happen because it's being already destroyed for
1775 // example)
1776 if ( window == m_staticBox )
1777 {
1778 m_staticBox = NULL;
1779 return true;
1780 }
1781
1782 return wxSizer::Detach( window );
1783 }
1784
1785 #endif // wxUSE_STATBOX
1786
1787 #if wxUSE_BUTTON
1788
1789 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1790 : wxBoxSizer(wxHORIZONTAL)
1791 {
1792 // Vertical buttons with lots of space on either side
1793 // looks rubbish on WinCE, so let's not do this for now.
1794 // If we are going to use vertical buttons, we should
1795 // put the sizer to the right of other controls in the dialog,
1796 // and that's beyond the scope of this sizer.
1797 #ifndef __WXWINCE__
1798 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1799 // If we have a PDA screen, put yes/no button over
1800 // all other buttons, otherwise on the left side.
1801 if (is_pda)
1802 m_orient = wxVERTICAL;
1803 #endif
1804
1805 m_buttonAffirmative = NULL;
1806 m_buttonApply = NULL;
1807 m_buttonNegative = NULL;
1808 m_buttonCancel = NULL;
1809 m_buttonHelp = NULL;
1810 }
1811
1812 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1813 {
1814 switch (mybutton->GetId())
1815 {
1816 case wxID_OK:
1817 case wxID_YES:
1818 case wxID_SAVE:
1819 m_buttonAffirmative = mybutton;
1820 break;
1821 case wxID_APPLY:
1822 m_buttonApply = mybutton;
1823 break;
1824 case wxID_NO:
1825 m_buttonNegative = mybutton;
1826 break;
1827 case wxID_CANCEL:
1828 m_buttonCancel = mybutton;
1829 break;
1830 case wxID_HELP:
1831 case wxID_CONTEXT_HELP:
1832 m_buttonHelp = mybutton;
1833 break;
1834 default:
1835 break;
1836 }
1837 }
1838
1839 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1840 {
1841 m_buttonAffirmative = button;
1842 }
1843
1844 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1845 {
1846 m_buttonNegative = button;
1847 }
1848
1849 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1850 {
1851 m_buttonCancel = button;
1852 }
1853
1854 void wxStdDialogButtonSizer::Realize()
1855 {
1856 #ifdef __WXMAC__
1857 Add(0, 0, 0, wxLEFT, 6);
1858 if (m_buttonHelp)
1859 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1860
1861 if (m_buttonNegative){
1862 // HIG POLICE BULLETIN - destructive buttons need extra padding
1863 // 24 pixels on either side
1864 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1865 }
1866
1867 // extra whitespace between help/negative and cancel/ok buttons
1868 Add(0, 0, 1, wxEXPAND, 0);
1869
1870 if (m_buttonCancel){
1871 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1872 // Cancel or help should be default
1873 // m_buttonCancel->SetDefaultButton();
1874 }
1875
1876 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1877 // figure the best place is between Cancel and OK
1878 if (m_buttonApply)
1879 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1880
1881 if (m_buttonAffirmative){
1882 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1883
1884 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1885 // these buttons have set labels under Mac so we should use them
1886 m_buttonAffirmative->SetLabel(_("Save"));
1887 m_buttonNegative->SetLabel(_("Don't Save"));
1888 }
1889 }
1890
1891 // Extra space around and at the right
1892 Add(12, 24);
1893 #elif defined(__WXGTK20__)
1894 Add(0, 0, 0, wxLEFT, 9);
1895 if (m_buttonHelp)
1896 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1897
1898 // extra whitespace between help and cancel/ok buttons
1899 Add(0, 0, 1, wxEXPAND, 0);
1900
1901 if (m_buttonNegative){
1902 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1903 }
1904
1905 if (m_buttonCancel){
1906 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1907 // Cancel or help should be default
1908 // m_buttonCancel->SetDefaultButton();
1909 }
1910
1911 if (m_buttonApply)
1912 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1913
1914 if (m_buttonAffirmative)
1915 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1916 #elif defined(__WXMSW__)
1917 // Windows
1918
1919 // right-justify buttons
1920 Add(0, 0, 1, wxEXPAND, 0);
1921
1922 if (m_buttonAffirmative){
1923 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
1924 }
1925
1926 if (m_buttonNegative){
1927 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
1928 }
1929
1930 if (m_buttonCancel){
1931 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
1932 }
1933 if (m_buttonApply)
1934 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
1935
1936 if (m_buttonHelp)
1937 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
1938 #else
1939 // GTK+1 and any other platform
1940
1941 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
1942 if (m_buttonHelp)
1943 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1944
1945 // extra whitespace between help and cancel/ok buttons
1946 Add(0, 0, 1, wxEXPAND, 0);
1947
1948 if (m_buttonApply)
1949 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1950
1951 if (m_buttonAffirmative){
1952 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1953 }
1954
1955 if (m_buttonNegative){
1956 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1957 }
1958
1959 if (m_buttonCancel){
1960 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
1961 // Cancel or help should be default
1962 // m_buttonCancel->SetDefaultButton();
1963 }
1964
1965 #endif
1966 }
1967
1968 #endif // wxUSE_BUTTON
1969
1970 #if WXWIN_COMPATIBILITY_2_4
1971
1972 // ----------------------------------------------------------------------------
1973 // wxNotebookSizer
1974 // ----------------------------------------------------------------------------
1975
1976 #if wxUSE_BOOKCTRL
1977 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1978 #if wxUSE_NOTEBOOK
1979 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1980 #endif // wxUSE_NOTEBOOK
1981 #endif // wxUSE_BOOKCTRL
1982
1983 #if wxUSE_BOOKCTRL
1984
1985 #if WXWIN_COMPATIBILITY_2_6
1986
1987 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
1988 : m_bookctrl(bookctrl)
1989 {
1990 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
1991 }
1992
1993 #endif // WXWIN_COMPATIBILITY_2_6
1994
1995 void wxBookCtrlSizer::RecalcSizes()
1996 {
1997 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1998 }
1999
2000 wxSize wxBookCtrlSizer::CalcMin()
2001 {
2002 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
2003
2004 sizeBorder.x += 5;
2005 sizeBorder.y += 5;
2006
2007 if ( m_bookctrl->GetPageCount() == 0 )
2008 {
2009 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
2010 }
2011
2012 int maxX = 0;
2013 int maxY = 0;
2014
2015 wxWindowList::compatibility_iterator
2016 node = m_bookctrl->GetChildren().GetFirst();
2017 while (node)
2018 {
2019 wxWindow *item = node->GetData();
2020 wxSizer *itemsizer = item->GetSizer();
2021
2022 if (itemsizer)
2023 {
2024 wxSize subsize( itemsizer->CalcMin() );
2025
2026 if (subsize.x > maxX)
2027 maxX = subsize.x;
2028 if (subsize.y > maxY)
2029 maxY = subsize.y;
2030 }
2031
2032 node = node->GetNext();
2033 }
2034
2035 return wxSize( maxX, maxY ) + sizeBorder;
2036 }
2037
2038 #if wxUSE_NOTEBOOK
2039
2040 #if WXWIN_COMPATIBILITY_2_6
2041
2042 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
2043 {
2044 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
2045 m_bookctrl = nb;
2046 }
2047
2048 #endif // WXWIN_COMPATIBILITY_2_6
2049
2050 #endif // wxUSE_NOTEBOOOK
2051 #endif // wxUSE_BOOKCTRL
2052
2053 #endif // WXWIN_COMPATIBILITY_2_4