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