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