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