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