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