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