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