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