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