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