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