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