]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
Don't trigger kill focus event twice
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/common/sizer.cpp
3 // Purpose:     provide new wxSizer class for layout
4 // Author:      Robert Roebling and Robin Dunn, contributions by
5 //              Dirk Holtwick, Ron Lee
6 // Modified by: Ron Lee
7 // Created:
8 // RCS-ID:      $Id$
9 // Copyright:   (c) Robin Dunn, Robert Roebling
10 // Licence:     wxWindows licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // For compilers that support precompilation, includes "wx.h".
14 #include "wx/wxprec.h"
15
16 #ifdef __BORLANDC__
17     #pragma hdrstop
18 #endif
19
20 #include "wx/display.h"
21 #include "wx/sizer.h"
22 #include "wx/private/flagscheck.h"
23
24 #ifndef WX_PRECOMP
25     #include "wx/string.h"
26     #include "wx/intl.h"
27     #include "wx/math.h"
28     #include "wx/utils.h"
29     #include "wx/settings.h"
30     #include "wx/button.h"
31     #include "wx/statbox.h"
32     #include "wx/toplevel.h"
33 #endif // WX_PRECOMP
34
35 #include "wx/listimpl.cpp"
36
37
38 //---------------------------------------------------------------------------
39
40 IMPLEMENT_CLASS(wxSizerItem, wxObject)
41 IMPLEMENT_CLASS(wxSizer, wxObject)
42 IMPLEMENT_CLASS(wxGridSizer, wxSizer)
43 IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer)
44 IMPLEMENT_CLASS(wxBoxSizer, wxSizer)
45 #if wxUSE_STATBOX
46 IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer)
47 #endif
48 #if wxUSE_BUTTON
49 IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer)
50 #endif
51
52 WX_DEFINE_EXPORTED_LIST( wxSizerItemList )
53
54 /*
55     TODO PROPERTIES
56       sizeritem
57         object
58         object_ref
59           minsize
60           option
61           flag
62           border
63      spacer
64         option
65         flag
66         borfder
67     boxsizer
68        orient
69     staticboxsizer
70        orient
71        label
72     gridsizer
73        rows
74        cols
75        vgap
76        hgap
77     flexgridsizer
78        rows
79        cols
80        vgap
81        hgap
82        growablerows
83        growablecols
84     minsize
85 */
86
87 // ----------------------------------------------------------------------------
88 // wxSizerItem
89 // ----------------------------------------------------------------------------
90
91 // check for flags conflicts
92 static const int SIZER_FLAGS_MASK =
93     wxADD_FLAG(wxCENTRE,
94     wxADD_FLAG(wxHORIZONTAL,
95     wxADD_FLAG(wxVERTICAL,
96     wxADD_FLAG(wxLEFT,
97     wxADD_FLAG(wxRIGHT,
98     wxADD_FLAG(wxUP,
99     wxADD_FLAG(wxDOWN,
100     wxADD_FLAG(wxALIGN_NOT,
101     wxADD_FLAG(wxALIGN_CENTER_HORIZONTAL,
102     wxADD_FLAG(wxALIGN_RIGHT,
103     wxADD_FLAG(wxALIGN_BOTTOM,
104     wxADD_FLAG(wxALIGN_CENTER_VERTICAL,
105     wxADD_FLAG(wxFIXED_MINSIZE,
106     wxADD_FLAG(wxRESERVE_SPACE_EVEN_IF_HIDDEN,
107     wxADD_FLAG(wxSTRETCH_NOT,
108     wxADD_FLAG(wxSHRINK,
109     wxADD_FLAG(wxGROW,
110     wxADD_FLAG(wxSHAPED,
111     0))))))))))))))))));
112
113 #define ASSERT_VALID_SIZER_FLAGS(f)  wxASSERT_VALID_FLAGS(f, SIZER_FLAGS_MASK)
114
115
116 void wxSizerItem::Init(const wxSizerFlags& flags)
117 {
118     Init();
119
120     m_proportion = flags.GetProportion();
121     m_flag = flags.GetFlags();
122     m_border = flags.GetBorderInPixels();
123
124     ASSERT_VALID_SIZER_FLAGS( m_flag );
125 }
126
127 wxSizerItem::wxSizerItem()
128 {
129     Init();
130
131     m_proportion = 0;
132     m_border = 0;
133     m_flag = 0;
134     m_id = wxID_NONE;
135 }
136
137 // window item
138 void wxSizerItem::DoSetWindow(wxWindow *window)
139 {
140     wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") );
141
142     m_kind = Item_Window;
143     m_window = window;
144
145     // window doesn't become smaller than its initial size, whatever happens
146     m_minSize = window->GetSize();
147
148     if ( m_flag & wxFIXED_MINSIZE )
149         window->SetMinSize(m_minSize);
150
151     // aspect ratio calculated from initial size
152     SetRatio(m_minSize);
153 }
154
155 wxSizerItem::wxSizerItem(wxWindow *window,
156                          int proportion,
157                          int flag,
158                          int border,
159                          wxObject* userData)
160            : m_kind(Item_None),
161              m_proportion(proportion),
162              m_border(border),
163              m_flag(flag),
164              m_id(wxID_NONE),
165              m_userData(userData)
166 {
167     ASSERT_VALID_SIZER_FLAGS( m_flag );
168
169     DoSetWindow(window);
170 }
171
172 // sizer item
173 void wxSizerItem::DoSetSizer(wxSizer *sizer)
174 {
175     m_kind = Item_Sizer;
176     m_sizer = sizer;
177 }
178
179 wxSizerItem::wxSizerItem(wxSizer *sizer,
180                          int proportion,
181                          int flag,
182                          int border,
183                          wxObject* userData)
184            : m_kind(Item_None),
185              m_sizer(NULL),
186              m_proportion(proportion),
187              m_border(border),
188              m_flag(flag),
189              m_id(wxID_NONE),
190              m_ratio(0.0),
191              m_userData(userData)
192 {
193     ASSERT_VALID_SIZER_FLAGS( m_flag );
194
195     DoSetSizer(sizer);
196
197     // m_minSize is set later
198 }
199
200 // spacer item
201 void wxSizerItem::DoSetSpacer(const wxSize& size)
202 {
203     m_kind = Item_Spacer;
204     m_spacer = new wxSizerSpacer(size);
205     m_minSize = size;
206     SetRatio(size);
207 }
208
209 wxSizerItem::wxSizerItem(int width,
210                          int height,
211                          int proportion,
212                          int flag,
213                          int border,
214                          wxObject* userData)
215            : m_kind(Item_None),
216              m_sizer(NULL),
217              m_minSize(width, height), // minimal size is the initial size
218              m_proportion(proportion),
219              m_border(border),
220              m_flag(flag),
221              m_id(wxID_NONE),
222              m_userData(userData)
223 {
224     ASSERT_VALID_SIZER_FLAGS( m_flag );
225
226     DoSetSpacer(wxSize(width, height));
227 }
228
229 wxSizerItem::~wxSizerItem()
230 {
231     delete m_userData;
232     Free();
233 }
234
235 void wxSizerItem::Free()
236 {
237     switch ( m_kind )
238     {
239         case Item_None:
240             break;
241
242         case Item_Window:
243             m_window->SetContainingSizer(NULL);
244             break;
245
246         case Item_Sizer:
247             delete m_sizer;
248             break;
249
250         case Item_Spacer:
251             delete m_spacer;
252             break;
253
254         case Item_Max:
255         default:
256             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
257     }
258
259     m_kind = Item_None;
260 }
261
262 wxSize wxSizerItem::GetSpacer() const
263 {
264     wxSize size;
265     if ( m_kind == Item_Spacer )
266         size = m_spacer->GetSize();
267
268     return size;
269 }
270
271
272 wxSize wxSizerItem::GetSize() const
273 {
274     wxSize ret;
275     switch ( m_kind )
276     {
277         case Item_None:
278             break;
279
280         case Item_Window:
281             ret = m_window->GetSize();
282             break;
283
284         case Item_Sizer:
285             ret = m_sizer->GetSize();
286             break;
287
288         case Item_Spacer:
289             ret = m_spacer->GetSize();
290             break;
291
292         case Item_Max:
293         default:
294             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
295     }
296
297     if (m_flag & wxWEST)
298         ret.x += m_border;
299     if (m_flag & wxEAST)
300         ret.x += m_border;
301     if (m_flag & wxNORTH)
302         ret.y += m_border;
303     if (m_flag & wxSOUTH)
304         ret.y += m_border;
305
306     return ret;
307 }
308
309 bool wxSizerItem::InformFirstDirection(int direction, int size, int availableOtherDir)
310 {
311     // The size that come here will be including borders. Child items should get it
312     // without borders.
313     if( size>0 )
314     {
315         if( direction==wxHORIZONTAL )
316         {
317             if (m_flag & wxWEST)
318                 size -= m_border;
319             if (m_flag & wxEAST)
320                 size -= m_border;
321         }
322         else if( direction==wxVERTICAL )
323         {
324             if (m_flag & wxNORTH)
325                 size -= m_border;
326             if (m_flag & wxSOUTH)
327                 size -= m_border;
328         }
329     }
330
331     bool didUse = false;
332     // Pass the information along to the held object
333     if (IsSizer())
334     {
335         didUse = GetSizer()->InformFirstDirection(direction,size,availableOtherDir);
336         if (didUse)
337             m_minSize = GetSizer()->CalcMin();
338     }
339     else if (IsWindow())
340     {
341         didUse =  GetWindow()->InformFirstDirection(direction,size,availableOtherDir);
342         if (didUse)
343             m_minSize = m_window->GetEffectiveMinSize();
344
345         // This information is useful for items with wxSHAPED flag, since
346         // we can request an optimal min size for such an item. Even if
347         // we overwrite the m_minSize member here, we can read it back from
348         // the owned window (happens automatically).
349         if( (m_flag & wxSHAPED) && (m_flag & wxEXPAND) && direction )
350         {
351             if( !wxIsNullDouble(m_ratio) )
352             {
353                 wxCHECK_MSG( (m_proportion==0), false, _T("Shaped item, non-zero proportion in wxSizerItem::InformFirstDirection()") );
354                 if( direction==wxHORIZONTAL && !wxIsNullDouble(m_ratio) )
355                 {
356                     // Clip size so that we don't take too much
357                     if( availableOtherDir>=0 && int(size/m_ratio)-m_minSize.y>availableOtherDir )
358                         size = int((availableOtherDir+m_minSize.y)*m_ratio);
359                     m_minSize = wxSize(size,int(size/m_ratio));
360                 }
361                 else if( direction==wxVERTICAL )
362                 {
363                     // Clip size so that we don't take too much
364                     if( availableOtherDir>=0 && int(size*m_ratio)-m_minSize.x>availableOtherDir )
365                         size = int((availableOtherDir+m_minSize.x)/m_ratio);
366                     m_minSize = wxSize(int(size*m_ratio),size);
367                 }
368                 didUse = true;
369             }
370         }
371     }
372
373     return didUse;
374 }
375
376 wxSize wxSizerItem::CalcMin()
377 {
378     if (IsSizer())
379     {
380         m_minSize = m_sizer->GetMinSize();
381
382         // if we have to preserve aspect ratio _AND_ this is
383         // the first-time calculation, consider ret to be initial size
384         if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) )
385             SetRatio(m_minSize);
386     }
387     else if ( IsWindow() )
388     {
389         // Since the size of the window may change during runtime, we
390         // should use the current minimal/best size.
391         m_minSize = m_window->GetEffectiveMinSize();
392     }
393
394     return GetMinSizeWithBorder();
395 }
396
397 wxSize wxSizerItem::GetMinSizeWithBorder() const
398 {
399     wxSize ret = m_minSize;
400
401     if (m_flag & wxWEST)
402         ret.x += m_border;
403     if (m_flag & wxEAST)
404         ret.x += m_border;
405     if (m_flag & wxNORTH)
406         ret.y += m_border;
407     if (m_flag & wxSOUTH)
408         ret.y += m_border;
409
410     return ret;
411 }
412
413
414 void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ )
415 {
416     wxPoint pos = pos_;
417     wxSize size = size_;
418     if (m_flag & wxSHAPED)
419     {
420         // adjust aspect ratio
421         int rwidth = (int) (size.y * m_ratio);
422         if (rwidth > size.x)
423         {
424             // fit horizontally
425             int rheight = (int) (size.x / m_ratio);
426             // add vertical space
427             if (m_flag & wxALIGN_CENTER_VERTICAL)
428                 pos.y += (size.y - rheight) / 2;
429             else if (m_flag & wxALIGN_BOTTOM)
430                 pos.y += (size.y - rheight);
431             // use reduced dimensions
432             size.y =rheight;
433         }
434         else if (rwidth < size.x)
435         {
436             // add horizontal space
437             if (m_flag & wxALIGN_CENTER_HORIZONTAL)
438                 pos.x += (size.x - rwidth) / 2;
439             else if (m_flag & wxALIGN_RIGHT)
440                 pos.x += (size.x - rwidth);
441             size.x = rwidth;
442         }
443     }
444
445     // This is what GetPosition() returns. Since we calculate
446     // borders afterwards, GetPosition() will be the left/top
447     // corner of the surrounding border.
448     m_pos = pos;
449
450     if (m_flag & wxWEST)
451     {
452         pos.x += m_border;
453         size.x -= m_border;
454     }
455     if (m_flag & wxEAST)
456     {
457         size.x -= m_border;
458     }
459     if (m_flag & wxNORTH)
460     {
461         pos.y += m_border;
462         size.y -= m_border;
463     }
464     if (m_flag & wxSOUTH)
465     {
466         size.y -= m_border;
467     }
468
469     if (size.x < 0)
470         size.x = 0;
471     if (size.y < 0)
472         size.y = 0;
473
474     m_rect = wxRect(pos, size);
475
476     switch ( m_kind )
477     {
478         case Item_None:
479             wxFAIL_MSG( _T("can't set size of uninitialized sizer item") );
480             break;
481
482         case Item_Window:
483             m_window->SetSize(pos.x, pos.y, size.x, size.y,
484                               wxSIZE_ALLOW_MINUS_ONE);
485             break;
486
487         case Item_Sizer:
488             m_sizer->SetDimension(pos.x, pos.y, size.x, size.y);
489             break;
490
491         case Item_Spacer:
492             m_spacer->SetSize(size);
493             break;
494
495         case Item_Max:
496         default:
497             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
498     }
499 }
500
501 void wxSizerItem::DeleteWindows()
502 {
503     switch ( m_kind )
504     {
505         case Item_None:
506         case Item_Spacer:
507             break;
508
509         case Item_Window:
510             //We are deleting the window from this sizer - normally
511             //the window destroys the sizer associated with it,
512             //which might destroy this, which we don't want
513             m_window->SetContainingSizer(NULL);
514             m_window->Destroy();
515             //Putting this after the switch will result in a spacer
516             //not being deleted properly on destruction
517             m_kind = Item_None;
518             break;
519
520         case Item_Sizer:
521             m_sizer->DeleteWindows();
522             break;
523
524         case Item_Max:
525         default:
526             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
527     }
528
529 }
530
531 void wxSizerItem::Show( bool show )
532 {
533     switch ( m_kind )
534     {
535         case Item_None:
536             wxFAIL_MSG( _T("can't show uninitialized sizer item") );
537             break;
538
539         case Item_Window:
540             m_window->Show(show);
541             break;
542
543         case Item_Sizer:
544             m_sizer->Show(show);
545             break;
546
547         case Item_Spacer:
548             m_spacer->Show(show);
549             break;
550
551         case Item_Max:
552         default:
553             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
554     }
555 }
556
557 bool wxSizerItem::IsShown() const
558 {
559     if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN )
560         return true;
561
562     switch ( m_kind )
563     {
564         case Item_None:
565             // we may be called from CalcMin(), just return false so that we're
566             // not used
567             break;
568
569         case Item_Window:
570             return m_window->IsShown();
571
572         case Item_Sizer:
573             // arbitrarily decide that if at least one of our elements is
574             // shown, so are we (this arbitrariness is the reason for
575             // deprecating this function)
576             {
577                 // Some apps (such as dialog editors) depend on an empty sizer still
578                 // being laid out correctly and reporting the correct size and position.
579                 if (m_sizer->GetChildren().GetCount() == 0)
580                     return true;
581
582                 for ( wxSizerItemList::compatibility_iterator
583                         node = m_sizer->GetChildren().GetFirst();
584                       node;
585                       node = node->GetNext() )
586                 {
587                     if ( node->GetData()->IsShown() )
588                         return true;
589                 }
590             }
591             return false;
592
593         case Item_Spacer:
594             return m_spacer->IsShown();
595
596         case Item_Max:
597         default:
598             wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
599     }
600
601     return false;
602 }
603
604 #if WXWIN_COMPATIBILITY_2_6
605 void wxSizerItem::SetOption( int option )
606 {
607     SetProportion( option );
608 }
609
610 int wxSizerItem::GetOption() const
611 {
612     return GetProportion();
613 }
614 #endif // WXWIN_COMPATIBILITY_2_6
615
616
617 //---------------------------------------------------------------------------
618 // wxSizer
619 //---------------------------------------------------------------------------
620
621 wxSizer::~wxSizer()
622 {
623     WX_CLEAR_LIST(wxSizerItemList, m_children);
624 }
625
626 wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
627 {
628     m_children.Insert( index, item );
629
630     if ( item->GetWindow() )
631         item->GetWindow()->SetContainingSizer( this );
632
633     if ( item->GetSizer() )
634         item->GetSizer()->SetContainingWindow( m_containingWindow );
635
636     return item;
637 }
638
639 void wxSizer::SetContainingWindow(wxWindow *win)
640 {
641     if ( win == m_containingWindow )
642         return;
643
644     m_containingWindow = win;
645
646     // set the same window for all nested sizers as well, they also are in the
647     // same window
648     for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
649           node;
650           node = node->GetNext() )
651     {
652         wxSizerItem *const item = node->GetData();
653         wxSizer *const sizer = item->GetSizer();
654
655         if ( sizer )
656         {
657             sizer->SetContainingWindow(win);
658         }
659     }
660 }
661
662 #if WXWIN_COMPATIBILITY_2_6
663 bool wxSizer::Remove( wxWindow *window )
664 {
665     return Detach( window );
666 }
667 #endif // WXWIN_COMPATIBILITY_2_6
668
669 bool wxSizer::Remove( wxSizer *sizer )
670 {
671     wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
672
673     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
674     while (node)
675     {
676         wxSizerItem     *item = node->GetData();
677
678         if (item->GetSizer() == sizer)
679         {
680             delete item;
681             m_children.Erase( node );
682             return true;
683         }
684
685         node = node->GetNext();
686     }
687
688     return false;
689 }
690
691 bool wxSizer::Remove( int index )
692 {
693     wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
694                  false,
695                  _T("Remove index is out of range") );
696
697     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
698
699     wxCHECK_MSG( node, false, _T("Failed to find child node") );
700
701     delete node->GetData();
702     m_children.Erase( node );
703
704     return true;
705 }
706
707 bool wxSizer::Detach( wxSizer *sizer )
708 {
709     wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
710
711     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
712     while (node)
713     {
714         wxSizerItem     *item = node->GetData();
715
716         if (item->GetSizer() == sizer)
717         {
718             item->DetachSizer();
719             delete item;
720             m_children.Erase( node );
721             return true;
722         }
723         node = node->GetNext();
724     }
725
726     return false;
727 }
728
729 bool wxSizer::Detach( wxWindow *window )
730 {
731     wxASSERT_MSG( window, _T("Detaching NULL window") );
732
733     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
734     while (node)
735     {
736         wxSizerItem     *item = node->GetData();
737
738         if (item->GetWindow() == window)
739         {
740             delete item;
741             m_children.Erase( node );
742             return true;
743         }
744         node = node->GetNext();
745     }
746
747     return false;
748 }
749
750 bool wxSizer::Detach( int index )
751 {
752     wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
753                  false,
754                  _T("Detach index is out of range") );
755
756     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
757
758     wxCHECK_MSG( node, false, _T("Failed to find child node") );
759
760     wxSizerItem *item = node->GetData();
761
762     if ( item->IsSizer() )
763         item->DetachSizer();
764
765     delete item;
766     m_children.Erase( node );
767     return true;
768 }
769
770 bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive )
771 {
772     wxASSERT_MSG( oldwin, _T("Replacing NULL window") );
773     wxASSERT_MSG( newwin, _T("Replacing with NULL window") );
774
775     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
776     while (node)
777     {
778         wxSizerItem     *item = node->GetData();
779
780         if (item->GetWindow() == oldwin)
781         {
782             item->AssignWindow(newwin);
783             newwin->SetContainingSizer( this );
784             return true;
785         }
786         else if (recursive && item->IsSizer())
787         {
788             if (item->GetSizer()->Replace( oldwin, newwin, true ))
789                 return true;
790         }
791
792         node = node->GetNext();
793     }
794
795     return false;
796 }
797
798 bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive )
799 {
800     wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") );
801     wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") );
802
803     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
804     while (node)
805     {
806         wxSizerItem     *item = node->GetData();
807
808         if (item->GetSizer() == oldsz)
809         {
810             item->AssignSizer(newsz);
811             return true;
812         }
813         else if (recursive && item->IsSizer())
814         {
815             if (item->GetSizer()->Replace( oldsz, newsz, true ))
816                 return true;
817         }
818
819         node = node->GetNext();
820     }
821
822     return false;
823 }
824
825 bool wxSizer::Replace( size_t old, wxSizerItem *newitem )
826 {
827     wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") );
828     wxASSERT_MSG( newitem, _T("Replacing with NULL item") );
829
830     wxSizerItemList::compatibility_iterator node = m_children.Item( old );
831
832     wxCHECK_MSG( node, false, _T("Failed to find child node") );
833
834     wxSizerItem *item = node->GetData();
835     node->SetData(newitem);
836     delete item;
837
838     return true;
839 }
840
841 void wxSizer::Clear( bool delete_windows )
842 {
843     // First clear the ContainingSizer pointers
844     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
845     while (node)
846     {
847         wxSizerItem     *item = node->GetData();
848
849         if (item->IsWindow())
850             item->GetWindow()->SetContainingSizer( NULL );
851         node = node->GetNext();
852     }
853
854     // Destroy the windows if needed
855     if (delete_windows)
856         DeleteWindows();
857
858     // Now empty the list
859     WX_CLEAR_LIST(wxSizerItemList, m_children);
860 }
861
862 void wxSizer::DeleteWindows()
863 {
864     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
865     while (node)
866     {
867         wxSizerItem     *item = node->GetData();
868
869         item->DeleteWindows();
870         node = node->GetNext();
871     }
872 }
873
874 wxSize wxSizer::ComputeFittingClientSize(wxWindow *window)
875 {
876     wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
877
878     // take the min size by default and limit it by max size
879     wxSize size = GetMinClientSize(window);
880     wxSize sizeMax;
881
882     wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow);
883     if ( tlw )
884     {
885         // hack for small screen devices where TLWs are always full screen
886         if ( tlw->IsAlwaysMaximized() )
887         {
888             return tlw->GetClientSize();
889         }
890
891         // limit the window to the size of the display it is on
892         int disp = wxDisplay::GetFromWindow(window);
893         if ( disp == wxNOT_FOUND )
894         {
895             // or, if we don't know which one it is, of the main one
896             disp = 0;
897         }
898
899         sizeMax = wxDisplay(disp).GetClientArea().GetSize();
900
901         // space for decorations and toolbars etc.
902         sizeMax = tlw->WindowToClientSize(sizeMax);
903     }
904     else
905     {
906         sizeMax = GetMaxClientSize(window);
907     }
908
909     if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x )
910             size.x = sizeMax.x;
911     if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y )
912             size.y = sizeMax.y;
913
914     return size;
915 }
916
917 wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window)
918 {
919     wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
920
921     return window->ClientToWindowSize(ComputeFittingClientSize(window));
922 }
923
924 wxSize wxSizer::Fit( wxWindow *window )
925 {
926     wxCHECK_MSG( window, wxDefaultSize, "window can't be NULL" );
927
928     // set client size
929     window->SetClientSize(ComputeFittingClientSize(window));
930
931     // return entire size
932     return window->GetSize();
933 }
934
935 void wxSizer::FitInside( wxWindow *window )
936 {
937     wxSize size;
938     if (window->IsTopLevel())
939         size = VirtualFitSize( window );
940     else
941         size = GetMinClientSize( window );
942
943     window->SetVirtualSize( size );
944 }
945
946 void wxSizer::Layout()
947 {
948     // (re)calculates minimums needed for each item and other preparations
949     // for layout
950     CalcMin();
951
952     // Applies the layout and repositions/resizes the items
953     RecalcSizes();
954 }
955
956 void wxSizer::SetSizeHints( wxWindow *window )
957 {
958     // Preserve the window's max size hints, but set the
959     // lower bound according to the sizer calculations.
960
961     // This is equivalent to calling Fit(), except that we need to set
962     // the size hints _in between_ the two steps performed by Fit
963     // (1. ComputeFittingClientSize, 2. SetClientSize). That's because
964     // otherwise SetClientSize() could have no effect if there already are
965     // size hints in effect that forbid requested client size.
966
967     const wxSize clientSize = ComputeFittingClientSize(window);
968
969     window->SetMinClientSize(clientSize);
970     window->SetClientSize(clientSize);
971 }
972
973 #if WXWIN_COMPATIBILITY_2_8
974 void wxSizer::SetVirtualSizeHints( wxWindow *window )
975 {
976     FitInside( window );
977 }
978 #endif // WXWIN_COMPATIBILITY_2_8
979
980 // TODO on mac we need a function that determines how much free space this
981 // min size contains, in order to make sure that we have 20 pixels of free
982 // space around the controls
983 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
984 {
985     return window->WindowToClientSize(window->GetMaxSize());
986 }
987
988 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
989 {
990     return GetMinSize();  // Already returns client size.
991 }
992
993 wxSize wxSizer::VirtualFitSize( wxWindow *window )
994 {
995     wxSize size     = GetMinClientSize( window );
996     wxSize sizeMax  = GetMaxClientSize( window );
997
998     // Limit the size if sizeMax != wxDefaultSize
999
1000     if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
1001         size.x = sizeMax.x;
1002     if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
1003         size.y = sizeMax.y;
1004
1005     return size;
1006 }
1007
1008 void wxSizer::SetDimension( int x, int y, int width, int height )
1009 {
1010     m_position.x = x;
1011     m_position.y = y;
1012     m_size.x = width;
1013     m_size.y = height;
1014     Layout();
1015 }
1016
1017 wxSize wxSizer::GetMinSize()
1018 {
1019     wxSize ret( CalcMin() );
1020     if (ret.x < m_minSize.x) ret.x = m_minSize.x;
1021     if (ret.y < m_minSize.y) ret.y = m_minSize.y;
1022     return ret;
1023 }
1024
1025 void wxSizer::DoSetMinSize( int width, int height )
1026 {
1027     m_minSize.x = width;
1028     m_minSize.y = height;
1029 }
1030
1031 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
1032 {
1033     wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
1034
1035     // Is it our immediate child?
1036
1037     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1038     while (node)
1039     {
1040         wxSizerItem     *item = node->GetData();
1041
1042         if (item->GetWindow() == window)
1043         {
1044             item->SetMinSize( width, height );
1045             return true;
1046         }
1047         node = node->GetNext();
1048     }
1049
1050     // No?  Search any subsizers we own then
1051
1052     node = m_children.GetFirst();
1053     while (node)
1054     {
1055         wxSizerItem     *item = node->GetData();
1056
1057         if ( item->GetSizer() &&
1058              item->GetSizer()->DoSetItemMinSize( window, width, height ) )
1059         {
1060             // A child sizer found the requested windw, exit.
1061             return true;
1062         }
1063         node = node->GetNext();
1064     }
1065
1066     return false;
1067 }
1068
1069 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
1070 {
1071     wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
1072
1073     // Is it our immediate child?
1074
1075     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1076     while (node)
1077     {
1078         wxSizerItem     *item = node->GetData();
1079
1080         if (item->GetSizer() == sizer)
1081         {
1082             item->GetSizer()->DoSetMinSize( width, height );
1083             return true;
1084         }
1085         node = node->GetNext();
1086     }
1087
1088     // No?  Search any subsizers we own then
1089
1090     node = m_children.GetFirst();
1091     while (node)
1092     {
1093         wxSizerItem     *item = node->GetData();
1094
1095         if ( item->GetSizer() &&
1096              item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
1097         {
1098             // A child found the requested sizer, exit.
1099             return true;
1100         }
1101         node = node->GetNext();
1102     }
1103
1104     return false;
1105 }
1106
1107 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
1108 {
1109     wxSizerItemList::compatibility_iterator node = m_children.Item( index );
1110
1111     wxCHECK_MSG( node, false, _T("Failed to find child node") );
1112
1113     wxSizerItem     *item = node->GetData();
1114
1115     if (item->GetSizer())
1116     {
1117         // Sizers contains the minimal size in them, if not calculated ...
1118         item->GetSizer()->DoSetMinSize( width, height );
1119     }
1120     else
1121     {
1122         // ... but the minimal size of spacers and windows is stored via the item
1123         item->SetMinSize( width, height );
1124     }
1125
1126     return true;
1127 }
1128
1129 wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
1130 {
1131     wxASSERT_MSG( window, _T("GetItem for NULL window") );
1132
1133     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1134     while (node)
1135     {
1136         wxSizerItem     *item = node->GetData();
1137
1138         if (item->GetWindow() == window)
1139         {
1140             return item;
1141         }
1142         else if (recursive && item->IsSizer())
1143         {
1144             wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
1145             if (subitem)
1146                 return subitem;
1147         }
1148
1149         node = node->GetNext();
1150     }
1151
1152     return NULL;
1153 }
1154
1155 wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
1156 {
1157     wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
1158
1159     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1160     while (node)
1161     {
1162         wxSizerItem *item = node->GetData();
1163
1164         if (item->GetSizer() == sizer)
1165         {
1166             return item;
1167         }
1168         else if (recursive && item->IsSizer())
1169         {
1170             wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
1171             if (subitem)
1172                 return subitem;
1173         }
1174
1175         node = node->GetNext();
1176     }
1177
1178     return NULL;
1179 }
1180
1181 wxSizerItem* wxSizer::GetItem( size_t index )
1182 {
1183     wxCHECK_MSG( index < m_children.GetCount(),
1184                  NULL,
1185                  _T("GetItem index is out of range") );
1186
1187     return m_children.Item( index )->GetData();
1188 }
1189
1190 wxSizerItem* wxSizer::GetItemById( int id, bool recursive )
1191 {
1192     // This gets a sizer item by the id of the sizer item
1193     // and NOT the id of a window if the item is a window.
1194
1195     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1196     while (node)
1197     {
1198         wxSizerItem     *item = node->GetData();
1199
1200         if (item->GetId() == id)
1201         {
1202             return item;
1203         }
1204         else if (recursive && item->IsSizer())
1205         {
1206             wxSizerItem *subitem = item->GetSizer()->GetItemById( id, true );
1207             if (subitem)
1208                 return subitem;
1209         }
1210
1211         node = node->GetNext();
1212     }
1213
1214     return NULL;
1215 }
1216
1217 bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
1218 {
1219     wxSizerItem *item = GetItem( window, recursive );
1220
1221     if ( item )
1222     {
1223          item->Show( show );
1224          return true;
1225     }
1226
1227     return false;
1228 }
1229
1230 bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
1231 {
1232     wxSizerItem *item = GetItem( sizer, recursive );
1233
1234     if ( item )
1235     {
1236          item->Show( show );
1237          return true;
1238     }
1239
1240     return false;
1241 }
1242
1243 bool wxSizer::Show( size_t index, bool show)
1244 {
1245     wxSizerItem *item = GetItem( index );
1246
1247     if ( item )
1248     {
1249          item->Show( show );
1250          return true;
1251     }
1252
1253     return false;
1254 }
1255
1256 void wxSizer::ShowItems( bool show )
1257 {
1258     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1259     while (node)
1260     {
1261         node->GetData()->Show( show );
1262         node = node->GetNext();
1263     }
1264 }
1265
1266 bool wxSizer::IsShown( wxWindow *window ) const
1267 {
1268     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1269     while (node)
1270     {
1271         wxSizerItem     *item = node->GetData();
1272
1273         if (item->GetWindow() == window)
1274         {
1275             return item->IsShown();
1276         }
1277         node = node->GetNext();
1278     }
1279
1280     wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1281
1282     return false;
1283 }
1284
1285 bool wxSizer::IsShown( wxSizer *sizer ) const
1286 {
1287     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1288     while (node)
1289     {
1290         wxSizerItem     *item = node->GetData();
1291
1292         if (item->GetSizer() == sizer)
1293         {
1294             return item->IsShown();
1295         }
1296         node = node->GetNext();
1297     }
1298
1299     wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1300
1301     return false;
1302 }
1303
1304 bool wxSizer::IsShown( size_t index ) const
1305 {
1306     wxCHECK_MSG( index < m_children.GetCount(),
1307                  false,
1308                  _T("IsShown index is out of range") );
1309
1310     return m_children.Item( index )->GetData()->IsShown();
1311 }
1312
1313
1314 //---------------------------------------------------------------------------
1315 // wxGridSizer
1316 //---------------------------------------------------------------------------
1317
1318 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
1319     : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
1320     , m_cols( cols )
1321     , m_vgap( vgap )
1322     , m_hgap( hgap )
1323 {
1324 }
1325
1326 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
1327     : m_rows( cols == 0 ? 1 : 0 )
1328     , m_cols( cols )
1329     , m_vgap( vgap )
1330     , m_hgap( hgap )
1331 {
1332 }
1333
1334 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
1335 {
1336     int nitems = m_children.GetCount();
1337     if ( nitems)
1338     {
1339         if ( m_cols )
1340         {
1341             ncols = m_cols;
1342             nrows = (nitems + m_cols - 1) / m_cols;
1343         }
1344         else if ( m_rows )
1345         {
1346             ncols = (nitems + m_rows - 1) / m_rows;
1347             nrows = m_rows;
1348         }
1349         else // 0 columns, 0 rows?
1350         {
1351             wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
1352
1353             nrows = ncols = 0;
1354         }
1355     }
1356
1357     return nitems;
1358 }
1359
1360 void wxGridSizer::RecalcSizes()
1361 {
1362     int nitems, nrows, ncols;
1363     if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1364         return;
1365
1366     wxSize sz( GetSize() );
1367     wxPoint pt( GetPosition() );
1368
1369     int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1370     int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
1371
1372     int x = pt.x;
1373     for (int c = 0; c < ncols; c++)
1374     {
1375         int y = pt.y;
1376         for (int r = 0; r < nrows; r++)
1377         {
1378             int i = r * ncols + c;
1379             if (i < nitems)
1380             {
1381                 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1382
1383                 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
1384
1385                 SetItemBounds( node->GetData(), x, y, w, h);
1386             }
1387             y = y + h + m_vgap;
1388         }
1389         x = x + w + m_hgap;
1390     }
1391 }
1392
1393 wxSize wxGridSizer::CalcMin()
1394 {
1395     int nrows, ncols;
1396     if ( CalcRowsCols(nrows, ncols) == 0 )
1397         return wxSize();
1398
1399     // Find the max width and height for any component
1400     int w = 0;
1401     int h = 0;
1402
1403     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1404     while (node)
1405     {
1406         wxSizerItem     *item = node->GetData();
1407         wxSize           sz( item->CalcMin() );
1408
1409         w = wxMax( w, sz.x );
1410         h = wxMax( h, sz.y );
1411
1412         node = node->GetNext();
1413     }
1414
1415     // In case we have a nested sizer with a two step algo , give it
1416     // a chance to adjust to that (we give it width component)
1417     node = m_children.GetFirst();
1418     bool didChangeMinSize = false;
1419     while (node)
1420     {
1421         wxSizerItem     *item = node->GetData();
1422         didChangeMinSize |= item->InformFirstDirection( wxHORIZONTAL, w, -1 );
1423
1424         node = node->GetNext();
1425     }
1426
1427     // And redo iteration in case min size changed
1428     if( didChangeMinSize )
1429     {
1430         node = m_children.GetFirst();
1431         w = h = 0;
1432         while (node)
1433         {
1434             wxSizerItem     *item = node->GetData();
1435             wxSize           sz( item->GetMinSizeWithBorder() );
1436
1437             w = wxMax( w, sz.x );
1438             h = wxMax( h, sz.y );
1439
1440             node = node->GetNext();
1441         }
1442     }
1443
1444     return wxSize( ncols * w + (ncols-1) * m_hgap,
1445                    nrows * h + (nrows-1) * m_vgap );
1446 }
1447
1448 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1449 {
1450     wxPoint pt( x,y );
1451     wxSize sz( item->GetMinSizeWithBorder() );
1452     int flag = item->GetFlag();
1453
1454     if ((flag & wxEXPAND) || (flag & wxSHAPED))
1455     {
1456        sz = wxSize(w, h);
1457     }
1458     else
1459     {
1460         if (flag & wxALIGN_CENTER_HORIZONTAL)
1461         {
1462             pt.x = x + (w - sz.x) / 2;
1463         }
1464         else if (flag & wxALIGN_RIGHT)
1465         {
1466             pt.x = x + (w - sz.x);
1467         }
1468
1469         if (flag & wxALIGN_CENTER_VERTICAL)
1470         {
1471             pt.y = y + (h - sz.y) / 2;
1472         }
1473         else if (flag & wxALIGN_BOTTOM)
1474         {
1475             pt.y = y + (h - sz.y);
1476         }
1477     }
1478
1479     item->SetDimension(pt, sz);
1480 }
1481
1482 //---------------------------------------------------------------------------
1483 // wxFlexGridSizer
1484 //---------------------------------------------------------------------------
1485
1486 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1487                : wxGridSizer( rows, cols, vgap, hgap ),
1488                  m_flexDirection(wxBOTH),
1489                  m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1490 {
1491 }
1492
1493 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1494                : wxGridSizer( cols, vgap, hgap ),
1495                  m_flexDirection(wxBOTH),
1496                  m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1497 {
1498 }
1499
1500 wxFlexGridSizer::~wxFlexGridSizer()
1501 {
1502 }
1503
1504 void wxFlexGridSizer::RecalcSizes()
1505 {
1506     int nrows, ncols;
1507     if ( !CalcRowsCols(nrows, ncols) )
1508         return;
1509
1510     const wxPoint pt(GetPosition());
1511     const wxSize sz(GetSize());
1512
1513     AdjustForGrowables(sz);
1514
1515     wxSizerItemList::const_iterator i = m_children.begin();
1516     const wxSizerItemList::const_iterator end = m_children.end();
1517
1518     int y = 0;
1519     for ( int r = 0; r < nrows; r++ )
1520     {
1521         if ( m_rowHeights[r] == -1 )
1522         {
1523             // this row is entirely hidden, skip it
1524             for ( int c = 0; c < ncols; c++ )
1525             {
1526                 if ( i == end )
1527                     return;
1528
1529                 ++i;
1530             }
1531
1532             continue;
1533         }
1534
1535         const int hrow = m_rowHeights[r];
1536         int h = sz.y - y; // max remaining height, don't overflow it
1537         if ( hrow < h )
1538             h = hrow;
1539
1540         int x = 0;
1541         for ( int c = 0; c < ncols && i != end; c++, ++i )
1542         {
1543             const int wcol = m_colWidths[c];
1544
1545             if ( wcol == -1 )
1546                 continue;
1547
1548             int w = sz.x - x; // max possible value, ensure we don't overflow
1549             if ( wcol < w )
1550                 w = wcol;
1551
1552             SetItemBounds(*i, pt.x + x, pt.y + y, w, h);
1553
1554             x += wcol + m_hgap;
1555         }
1556
1557         if ( i == end )
1558             return;
1559
1560         y += hrow + m_vgap;
1561     }
1562 }
1563
1564 // helper function used in CalcMin() to sum up the sizes of non-hidden items
1565 static int SumArraySizes(const wxArrayInt& sizes, int gap)
1566 {
1567     // Sum total minimum size, including gaps between rows/columns.
1568     // -1 is used as a magic number meaning empty row/column.
1569     int total = 0;
1570
1571     const size_t count = sizes.size();
1572     for ( size_t n = 0; n < count; n++ )
1573     {
1574         if ( sizes[n] != -1 )
1575         {
1576             if ( total )
1577                 total += gap; // separate from the previous column
1578
1579             total += sizes[n];
1580         }
1581     }
1582
1583     return total;
1584 }
1585
1586 void wxFlexGridSizer::FindWidthsAndHeights(int nrows, int ncols)
1587 {
1588     // We have to recalculate the sizes in case the item minimum size has
1589     // changed since the previous layout, or the item has been hidden using
1590     // wxSizer::Show(). If all the items in a row/column are hidden, the final
1591     // dimension of the row/column will be -1, indicating that the column
1592     // itself is hidden.
1593     m_rowHeights.assign(nrows, -1);
1594     m_colWidths.assign(ncols, -1);
1595
1596     // n is the index of the item in left-to-right top-to-bottom order
1597     size_t n = 0;
1598     for ( wxSizerItemList::iterator i = m_children.begin();
1599           i != m_children.end();
1600           ++i, ++n )
1601     {
1602         wxSizerItem * const item = *i;
1603         if ( item->IsShown() )
1604         {
1605             // NOTE: Not doing the calculation here, this is just
1606             // for finding max values.
1607             const wxSize sz(item->GetMinSizeWithBorder());
1608
1609             const int row = n / ncols;
1610             const int col = n % ncols;
1611
1612             if ( sz.y > m_rowHeights[row] )
1613                 m_rowHeights[row] = sz.y;
1614             if ( sz.x > m_colWidths[col] )
1615                 m_colWidths[col] = sz.x;
1616         }
1617     }
1618
1619     AdjustForFlexDirection();
1620
1621     m_calculatedMinSize = wxSize(SumArraySizes(m_colWidths, m_hgap),
1622                                  SumArraySizes(m_rowHeights, m_vgap));
1623 }
1624
1625 wxSize wxFlexGridSizer::CalcMin()
1626 {
1627     int nrows,
1628         ncols;
1629
1630     // Number of rows/columns can change as items are added or removed.
1631     if ( !CalcRowsCols(nrows, ncols) )
1632         return wxSize();
1633
1634
1635     // We have to recalculate the sizes in case the item minimum size has
1636     // changed since the previous layout, or the item has been hidden using
1637     // wxSizer::Show(). If all the items in a row/column are hidden, the final
1638     // dimension of the row/column will be -1, indicating that the column
1639     // itself is hidden.
1640     m_rowHeights.assign(nrows, -1);
1641     m_colWidths.assign(ncols, -1);
1642
1643     // n is the index of the item in left-to-right top-to-bottom order
1644     size_t n = 0;
1645     for ( wxSizerItemList::iterator i = m_children.begin();
1646           i != m_children.end();
1647           ++i, ++n )
1648     {
1649         wxSizerItem * const item = *i;
1650         if ( item->IsShown() )
1651         {
1652             item->CalcMin();
1653         }
1654     }
1655
1656     // The stage of looking for max values in each row/column has been
1657     // made a separate function, since it's reused in AdjustForGrowables.
1658     FindWidthsAndHeights(nrows,ncols);
1659
1660     return m_calculatedMinSize;
1661 }
1662
1663 void wxFlexGridSizer::AdjustForFlexDirection()
1664 {
1665     // the logic in CalcMin works when we resize flexibly in both directions
1666     // but maybe this is not the case
1667     if ( m_flexDirection != wxBOTH )
1668     {
1669         // select the array corresponding to the direction in which we do *not*
1670         // resize flexibly
1671         wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1672                                                           : m_rowHeights;
1673
1674         const size_t count = array.GetCount();
1675
1676         // find the largest value in this array
1677         size_t n;
1678         int largest = 0;
1679
1680         for ( n = 0; n < count; ++n )
1681         {
1682             if ( array[n] > largest )
1683                 largest = array[n];
1684         }
1685
1686         // and now fill it with the largest value
1687         for ( n = 0; n < count; ++n )
1688         {
1689             // don't touch hidden rows
1690             if ( array[n] != -1 )
1691                 array[n] = largest;
1692         }
1693     }
1694 }
1695
1696 // helper of AdjustForGrowables() which is called for rows/columns separately
1697 //
1698 // parameters:
1699 //      delta: the extra space, we do nothing unless it's positive
1700 //      growable: indices or growable rows/cols in sizes array
1701 //      sizes: the height/widths of rows/cols to adjust
1702 //      proportions: proportions of the growable rows/cols or NULL if they all
1703 //                   should be assumed to have proportion of 1
1704 static void
1705 DoAdjustForGrowables(int delta,
1706                      const wxArrayInt& growable,
1707                      wxArrayInt& sizes,
1708                      const wxArrayInt *proportions)
1709 {
1710     if ( delta <= 0 )
1711         return;
1712
1713     // total sum of proportions of all non-hidden rows
1714     int sum_proportions = 0;
1715
1716     // number of currently shown growable rows
1717     int num = 0;
1718
1719     const int max_idx = sizes.size();
1720
1721     const size_t count = growable.size();
1722     size_t idx;
1723     for ( idx = 0; idx < count; idx++ )
1724     {
1725         // Since the number of rows/columns can change as items are
1726         // inserted/deleted, we need to verify at runtime that the
1727         // requested growable rows/columns are still valid.
1728         if ( growable[idx] >= max_idx )
1729             continue;
1730
1731         // If all items in a row/column are hidden, that row/column will
1732         // have a dimension of -1.  This causes the row/column to be
1733         // hidden completely.
1734         if ( sizes[growable[idx]] == -1 )
1735             continue;
1736
1737         if ( proportions )
1738             sum_proportions += (*proportions)[idx];
1739
1740         num++;
1741     }
1742
1743     if ( !num )
1744         return;
1745
1746     // the remaining extra free space, adjusted during each iteration
1747     for ( idx = 0; idx < count; idx++ )
1748     {
1749         if ( growable[idx] >= max_idx )
1750             continue;
1751
1752         if ( sizes[ growable[idx] ] == -1 )
1753             continue;
1754
1755         int cur_delta;
1756         if ( sum_proportions == 0 )
1757         {
1758             // no growable rows -- divide extra space evenly among all
1759             cur_delta = delta/num;
1760             num--;
1761         }
1762         else // allocate extra space proportionally
1763         {
1764             const int cur_prop = (*proportions)[idx];
1765             cur_delta = (delta*cur_prop)/sum_proportions;
1766             sum_proportions -= cur_prop;
1767         }
1768
1769         sizes[growable[idx]] += cur_delta;
1770         delta -= cur_delta;
1771     }
1772 }
1773
1774 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz)
1775 {
1776     if ( (m_flexDirection & wxHORIZONTAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
1777     {
1778         DoAdjustForGrowables
1779         (
1780             sz.x - m_calculatedMinSize.x,
1781             m_growableCols,
1782             m_colWidths,
1783             m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
1784                                                     : NULL
1785         );
1786
1787         // This gives nested objects that benefit from knowing one size
1788         // component in advance the chance to use that.
1789         bool didAdjustMinSize = false;
1790         int nrows, ncols;
1791         CalcRowsCols(nrows, ncols);
1792
1793         // Iterate over all items and inform about column width
1794         size_t n = 0;
1795         for ( wxSizerItemList::iterator i = m_children.begin();
1796               i != m_children.end();
1797               ++i, ++n )
1798         {
1799             const int col = n % ncols;
1800             didAdjustMinSize |= (*i)->InformFirstDirection(wxHORIZONTAL, m_colWidths[col], sz.y - m_calculatedMinSize.y);
1801     }
1802
1803         // Only redo if info was actually used
1804         if( didAdjustMinSize )
1805     {
1806         DoAdjustForGrowables
1807         (
1808             sz.x - m_calculatedMinSize.x,
1809             m_growableCols,
1810             m_colWidths,
1811             m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableColsProportions
1812                                                     : NULL
1813         );
1814     }
1815 }
1816
1817     if ( (m_flexDirection & wxVERTICAL) || (m_growMode != wxFLEX_GROWMODE_NONE) )
1818     {
1819         // pass NULL instead of proportions if the grow mode is ALL as we
1820         // should treat all rows as having proportion of 1 then
1821         DoAdjustForGrowables
1822         (
1823             sz.y - m_calculatedMinSize.y,
1824             m_growableRows,
1825             m_rowHeights,
1826             m_growMode == wxFLEX_GROWMODE_SPECIFIED ? &m_growableRowsProportions
1827                                                     : NULL
1828         );
1829     }
1830 }
1831
1832
1833 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1834 {
1835     m_growableRows.Add( idx );
1836     m_growableRowsProportions.Add( proportion );
1837 }
1838
1839 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1840 {
1841     m_growableCols.Add( idx );
1842     m_growableColsProportions.Add( proportion );
1843 }
1844
1845 // helper function for RemoveGrowableCol/Row()
1846 static void
1847 DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1848 {
1849     const size_t count = items.size();
1850     for ( size_t n = 0; n < count; n++ )
1851     {
1852         if ( (size_t)items[n] == idx )
1853         {
1854             items.RemoveAt(n);
1855             proportions.RemoveAt(n);
1856             return;
1857         }
1858     }
1859
1860     wxFAIL_MSG( _T("column/row is already not growable") );
1861 }
1862
1863 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1864 {
1865     DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1866 }
1867
1868 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1869 {
1870     DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
1871 }
1872
1873 //---------------------------------------------------------------------------
1874 // wxBoxSizer
1875 //---------------------------------------------------------------------------
1876
1877 void wxBoxSizer::RecalcSizes()
1878 {
1879     if ( m_children.empty() )
1880         return;
1881
1882     const wxCoord totalMinorSize = GetSizeInMinorDir(m_size);
1883
1884     // the amount of free space which we should redistribute among the
1885     // stretchable items (i.e. those with non zero proportion)
1886     int delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1887
1888
1889     // Inform child items about the size in minor direction, that can
1890     // change how much free space we have in major dir and how to distribute it.
1891     int majorMinSum = 0;
1892     wxSizerItemList::const_iterator i ;
1893     for ( i = m_children.begin();
1894           i != m_children.end();
1895           ++i )
1896     {
1897         wxSizerItem * const item = *i;
1898
1899         if ( !item->IsShown() )
1900             continue;
1901
1902         wxSize szMinPrev = item->GetMinSizeWithBorder();
1903         item->InformFirstDirection(m_orient^wxBOTH,totalMinorSize,delta);
1904         wxSize szMin = item->GetMinSizeWithBorder();
1905         int deltaChange = GetSizeInMajorDir(szMin-szMinPrev);
1906         if( deltaChange )
1907         {
1908             // Since we passed available space along to the item, it should not
1909             // take too much, so delta should not become negative.
1910             delta -= deltaChange;
1911         }
1912         majorMinSum += GetSizeInMajorDir(item->GetMinSizeWithBorder());
1913     }
1914     // And update our min size
1915     SizeInMajorDir(m_minSize) = majorMinSum;
1916
1917
1918     // might have a new delta now
1919     delta = GetSizeInMajorDir(m_size) - GetSizeInMajorDir(m_minSize);
1920
1921     // the position at which we put the next child
1922     wxPoint pt(m_position);
1923
1924     int totalProportion = m_totalProportion;
1925     for ( i = m_children.begin();
1926           i != m_children.end();
1927           ++i )
1928     {
1929         wxSizerItem * const item = *i;
1930
1931         if ( !item->IsShown() )
1932             continue;
1933
1934         const wxSize sizeThis(item->GetMinSizeWithBorder());
1935
1936         // adjust the size in the major direction using the proportion
1937         wxCoord majorSize = GetSizeInMajorDir(sizeThis);
1938         const int propItem = item->GetProportion();
1939         if ( propItem )
1940         {
1941             const int deltaItem = (delta * propItem) / totalProportion;
1942
1943             majorSize += deltaItem;
1944
1945             delta -= deltaItem;
1946             totalProportion -= propItem;
1947         }
1948
1949
1950         // apply the alignment in the minor direction
1951         wxPoint posChild(pt);
1952
1953         wxCoord minorSize = GetSizeInMinorDir(sizeThis);
1954         const int flag = item->GetFlag();
1955         if ( flag & (wxEXPAND | wxSHAPED) )
1956         {
1957             minorSize = totalMinorSize;
1958         }
1959         else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1960         {
1961             PosInMinorDir(posChild) += totalMinorSize - minorSize;
1962         }
1963         // NB: wxCENTRE is used here only for backwards compatibility,
1964         //     wxALIGN_CENTRE should be used in new code
1965         else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1966         {
1967             PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1968         }
1969
1970
1971         // apply RTL adjustment for horizontal sizers:
1972         if ( !IsVertical() && m_containingWindow )
1973         {
1974             posChild.x = m_containingWindow->AdjustForLayoutDirection
1975                                              (
1976                                                 posChild.x,
1977                                                 majorSize,
1978                                                 m_size.x
1979                                              );
1980         }
1981
1982         // finally set size of this child and advance to the next one
1983         item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1984
1985         PosInMajorDir(pt) += majorSize;
1986     }
1987 }
1988
1989 wxSize wxBoxSizer::CalcMin()
1990 {
1991     m_totalProportion = 0;
1992     m_minSize = wxSize(0, 0);
1993
1994     // calculate the minimal sizes for all items and count sum of proportions
1995     for ( wxSizerItemList::const_iterator i = m_children.begin();
1996           i != m_children.end();
1997           ++i )
1998     {
1999         wxSizerItem * const item = *i;
2000
2001         if ( !item->IsShown() )
2002             continue;
2003
2004         const wxSize sizeMinThis = item->CalcMin();
2005         SizeInMajorDir(m_minSize) += GetSizeInMajorDir(sizeMinThis);
2006         if ( GetSizeInMinorDir(sizeMinThis) > GetSizeInMinorDir(m_minSize) )
2007             SizeInMinorDir(m_minSize) = GetSizeInMinorDir(sizeMinThis);
2008
2009         m_totalProportion += item->GetProportion();
2010     }
2011
2012     return m_minSize;
2013 }
2014
2015 //---------------------------------------------------------------------------
2016 // wxWrapSizer
2017 //---------------------------------------------------------------------------
2018
2019 #define wxDEFAULT_PROPORTION_LAST    1000000
2020
2021 // User data to hold old proportion for last item on line
2022 // (which might be extended)
2023 struct wxPropHolder : public wxObject
2024 {
2025     wxPropHolder( ) : m_item(0), m_propOld(0)   { }
2026     void Init( wxSizerItem *item, int propOld ) { m_item=item; m_propOld=propOld; }
2027
2028     wxSizerItem *m_item;
2029     int          m_propOld;
2030 };
2031
2032 IMPLEMENT_DYNAMIC_CLASS(wxWrapSizer, wxBoxSizer);
2033
2034 wxWrapSizer::wxWrapSizer( int orient, int flags )
2035     : wxBoxSizer(orient),
2036       m_prim_size_last( -1 ),
2037       m_rows(orient^wxBOTH),
2038       m_flags(flags)
2039 {
2040 }
2041
2042 wxWrapSizer::~wxWrapSizer()
2043 {
2044     // Have to clear grand child items so that they're not deleted twice
2045     for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- )
2046     {
2047         wxSizer *psz = m_rows.GetItem((size_t)ix)->GetSizer();
2048         wxSizerItemList &sl = psz->GetChildren();
2049         while( sl.GetLast() )
2050             sl.Erase( sl.GetLast() );
2051     }
2052 }
2053
2054
2055 bool wxWrapSizer::InformFirstDirection( int direction, int size, int WXUNUSED(availableOtherDir) )
2056 {
2057     if( !direction )
2058     {
2059         // Better to keep value, then CalcMin will work better
2060         //m_prim_size_last = -1;
2061         return false;
2062     }
2063     if( direction==m_orient )
2064     {
2065         // The direction is same as our primary, so we can make use of it
2066         m_prim_size_last = size;
2067         return true;
2068     }
2069     else
2070         return false;
2071 }
2072
2073
2074 void wxWrapSizer::AdjustPropLastItem(wxSizer *psz, wxSizerItem *itemLast)
2075 {
2076     wxSizerItem *psi = m_rows.GetItem(psz);
2077     wxASSERT(psi);
2078     wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
2079     if ( !pph )
2080         psi->SetUserData( pph=new wxPropHolder );
2081
2082     pph->Init( itemLast, itemLast->GetProportion() );
2083     itemLast->SetProportion( wxDEFAULT_PROPORTION_LAST );
2084 }
2085
2086 void wxWrapSizer::RecalcSizes()
2087 {
2088     wxASSERT( m_orient&wxBOTH );
2089     if (m_children.GetCount() == 0)
2090         return;
2091
2092     // What we do here is to put our items into child box sizers,
2093     // as many of them as we have lines.
2094
2095     // Empty all items in all rows in owned sizer.
2096     // We have to access the list directly, since we don't want to
2097     // destroy the wxSizerItems.
2098     for( int ix=m_rows.GetChildren().GetCount()-1; ix>=0; ix-- ){
2099         wxSizerItem *psi = m_rows.GetItem( (size_t)ix );
2100
2101         // Restore proportion for last item on line (if item has not been deleted)
2102         wxPropHolder *pph = (wxPropHolder*)psi->GetUserData();
2103         if( pph && GetChildren().Find(pph->m_item) )
2104             pph->m_item->SetProportion(pph->m_propOld);
2105
2106         wxSizer *psz = psi->GetSizer();
2107         wxASSERT( psz );
2108         wxSizerItemList &sl = psz->GetChildren();
2109         while( sl.GetLast() )
2110             sl.Erase( sl.GetLast() );
2111     }
2112
2113     int lineSumMajor = 0;
2114     int majorSize = GetSizeInMajorDir(m_size);
2115
2116     // Make sure we have at least one child sizer
2117     m_n_line = 1;
2118     if( !m_rows.GetChildren().GetCount() )
2119         m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
2120
2121     // The sizer where to insert items in
2122     wxSizer *psz = m_rows.GetItem((size_t)0)->GetSizer();
2123     wxASSERT( psz );
2124
2125     // Now put our child items into child sizers instead
2126     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2127     wxSizerItem *item = NULL, *itemLast=NULL;
2128     while (node)
2129     {
2130         item = node->GetData();
2131         if ( item->IsShown() )
2132         {
2133             wxSize minSz = item->GetMinSize();
2134             int minSzMajor = GetSizeInMajorDir(minSz);
2135
2136             // More space on this line?
2137             if( !lineSumMajor || lineSumMajor+minSzMajor<=majorSize )
2138             {
2139                 lineSumMajor += minSzMajor;
2140             }
2141             else
2142             {
2143                 lineSumMajor = minSzMajor;
2144                 // Get a new empty sizer to insert into
2145                 if( (int)m_rows.GetChildren().GetCount()<=m_n_line )
2146                     m_rows.Add( new wxBoxSizer(GetOrientation()), 1, wxEXPAND );
2147
2148                 // If we have extend-last-on-each-line mode, then do so now
2149                 // Note: We must store old proportion value then.
2150                 if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
2151                     AdjustPropLastItem(psz,itemLast);
2152
2153                 // The sizer where to insert items in
2154                 psz = m_rows.GetItem(m_n_line++)->GetSizer();
2155             }
2156             itemLast = item;
2157             psz->Add( item );
2158             // If item is a window, it now has a pointer to the child sizer,
2159             // which is wrong. Set it to point to us.
2160             if( item->GetWindow() )
2161                 item->GetWindow()->SetContainingSizer( this );
2162         }
2163         node = node->GetNext();
2164     }
2165
2166     // If we have extend-last-on-each-line mode, then do so now
2167     if( m_flags&wxEXTEND_LAST_ON_EACH_LINE )
2168         AdjustPropLastItem(psz,itemLast);
2169
2170     // If we have more sizers than lines, remove them
2171     while( (int)m_rows.GetChildren().GetCount()>m_n_line )
2172         m_rows.Remove( m_n_line );
2173
2174     // Now do layout on row sizer
2175     m_rows.SetDimension( m_position.x, m_position.y, m_size.x, m_size.y );
2176
2177     // Remember this to next time (will be overridden by InformFirstDirection if used)
2178     m_prim_size_last = GetSizeInMajorDir(m_size);
2179 }
2180
2181
2182 wxSize wxWrapSizer::CalcMin()
2183 {
2184     if (m_children.GetCount() == 0)
2185         return wxSize();
2186
2187     // Algorithm for calculating min size: (assuming horizontal orientation)
2188     // X: Max width of all members
2189     // Y: Based on last X, calculate how many lines needed
2190     //    First time around, assume all items fits on one line
2191
2192     int maxMajor = 0;
2193     int minorSum = 0;
2194     int lineMaxMinor = 0;
2195     int lineSumMajor = 0;
2196     m_n_line = 0;
2197
2198     // precalc item minsizes and fit on lines (preliminary)
2199     wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
2200     while (node)
2201     {
2202         wxSizerItem *item = node->GetData();
2203         if ( item->IsShown() )
2204         {
2205             wxSize minSz = item->CalcMin();
2206             int szMajor = GetSizeInMajorDir(minSz);
2207             int szMinor = GetSizeInMinorDir(minSz);
2208             if( szMajor>maxMajor ) maxMajor = szMajor;
2209             // More space on this line?
2210             if( m_prim_size_last<0 || !lineSumMajor ||
2211                 lineSumMajor+szMajor<=m_prim_size_last )
2212             {
2213                 lineSumMajor += szMajor;
2214                 if( szMinor>lineMaxMinor )
2215                     lineMaxMinor = szMinor;
2216             }
2217             else
2218             {
2219                 minorSum += lineMaxMinor;    // Add height of highest item on last line
2220                 m_n_line++;
2221                 lineMaxMinor = szMinor;
2222                 lineSumMajor = szMajor;
2223             }
2224         }
2225         node = node->GetNext();
2226     }
2227     minorSum += lineMaxMinor;            // Add height of highest item on last line
2228
2229     m_minSize = SizeFromMajorMinor(maxMajor, minorSum);
2230     return m_minSize;
2231 }
2232
2233 //---------------------------------------------------------------------------
2234 // wxStaticBoxSizer
2235 //---------------------------------------------------------------------------
2236
2237 #if wxUSE_STATBOX
2238
2239 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
2240     : wxBoxSizer( orient ),
2241       m_staticBox( box )
2242 {
2243     wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
2244
2245     // do this so that our Detach() is called if the static box is destroyed
2246     // before we are
2247     m_staticBox->SetContainingSizer(this);
2248 }
2249
2250 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
2251                 : wxBoxSizer(orient),
2252                   m_staticBox(new wxStaticBox(win, wxID_ANY, s))
2253 {
2254     // same as above
2255     m_staticBox->SetContainingSizer(this);
2256 }
2257
2258 wxStaticBoxSizer::~wxStaticBoxSizer()
2259 {
2260     delete m_staticBox;
2261 }
2262
2263 static void GetStaticBoxBorders( wxStaticBox *box,
2264                                  int *borderTop,
2265                                  int *borderOther)
2266 {
2267     // this has to be done platform by platform as there is no way to
2268     // guess the thickness of a wxStaticBox border
2269     box->GetBordersForSizer(borderTop, borderOther);
2270 }
2271
2272 void wxStaticBoxSizer::RecalcSizes()
2273 {
2274     int top_border, other_border;
2275     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
2276
2277     m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
2278
2279     wxPoint old_pos( m_position );
2280     m_position.x += other_border;
2281     m_position.y += top_border;
2282     wxSize old_size( m_size );
2283     m_size.x -= 2*other_border;
2284     m_size.y -= top_border + other_border;
2285
2286     wxBoxSizer::RecalcSizes();
2287
2288     m_position = old_pos;
2289     m_size = old_size;
2290 }
2291
2292 wxSize wxStaticBoxSizer::CalcMin()
2293 {
2294     int top_border, other_border;
2295     GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
2296
2297     wxSize ret( wxBoxSizer::CalcMin() );
2298     ret.x += 2*other_border;
2299     ret.y += other_border + top_border;
2300
2301     return ret;
2302 }
2303
2304 void wxStaticBoxSizer::ShowItems( bool show )
2305 {
2306     m_staticBox->Show( show );
2307     wxBoxSizer::ShowItems( show );
2308 }
2309
2310 bool wxStaticBoxSizer::Detach( wxWindow *window )
2311 {
2312     // avoid deleting m_staticBox in our dtor if it's being detached from the
2313     // sizer (which can happen because it's being already destroyed for
2314     // example)
2315     if ( window == m_staticBox )
2316     {
2317         m_staticBox = NULL;
2318         return true;
2319     }
2320
2321     return wxSizer::Detach( window );
2322 }
2323
2324 #endif // wxUSE_STATBOX
2325
2326 #if wxUSE_BUTTON
2327
2328 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
2329     : wxBoxSizer(wxHORIZONTAL)
2330 {
2331     // Vertical buttons with lots of space on either side
2332     // looks rubbish on WinCE, so let's not do this for now.
2333     // If we are going to use vertical buttons, we should
2334     // put the sizer to the right of other controls in the dialog,
2335     // and that's beyond the scope of this sizer.
2336 #ifndef __WXWINCE__
2337     bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
2338     // If we have a PDA screen, put yes/no button over
2339     // all other buttons, otherwise on the left side.
2340     if (is_pda)
2341         m_orient = wxVERTICAL;
2342 #endif
2343
2344     m_buttonAffirmative = NULL;
2345     m_buttonApply = NULL;
2346     m_buttonNegative = NULL;
2347     m_buttonCancel = NULL;
2348     m_buttonHelp = NULL;
2349 }
2350
2351 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
2352 {
2353     switch (mybutton->GetId())
2354     {
2355         case wxID_OK:
2356         case wxID_YES:
2357         case wxID_SAVE:
2358             m_buttonAffirmative = mybutton;
2359             break;
2360         case wxID_APPLY:
2361             m_buttonApply = mybutton;
2362             break;
2363         case wxID_NO:
2364             m_buttonNegative = mybutton;
2365             break;
2366         case wxID_CANCEL:
2367         case wxID_CLOSE:
2368             m_buttonCancel = mybutton;
2369             break;
2370         case wxID_HELP:
2371         case wxID_CONTEXT_HELP:
2372             m_buttonHelp = mybutton;
2373             break;
2374         default:
2375             break;
2376     }
2377 }
2378
2379 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
2380 {
2381     m_buttonAffirmative = button;
2382 }
2383
2384 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
2385 {
2386     m_buttonNegative = button;
2387 }
2388
2389 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
2390 {
2391     m_buttonCancel = button;
2392 }
2393
2394 void wxStdDialogButtonSizer::Realize()
2395 {
2396 #ifdef __WXMAC__
2397         Add(0, 0, 0, wxLEFT, 6);
2398         if (m_buttonHelp)
2399             Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2400
2401         if (m_buttonNegative){
2402             // HIG POLICE BULLETIN - destructive buttons need extra padding
2403             // 24 pixels on either side
2404             Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
2405         }
2406
2407         // extra whitespace between help/negative and cancel/ok buttons
2408         Add(0, 0, 1, wxEXPAND, 0);
2409
2410         if (m_buttonCancel){
2411             Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2412             // Cancel or help should be default
2413             // m_buttonCancel->SetDefaultButton();
2414         }
2415
2416         // Ugh, Mac doesn't really have apply dialogs, so I'll just
2417         // figure the best place is between Cancel and OK
2418         if (m_buttonApply)
2419             Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
2420
2421         if (m_buttonAffirmative){
2422             Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
2423
2424             if (m_buttonAffirmative->GetId() == wxID_SAVE){
2425                 // these buttons have set labels under Mac so we should use them
2426                 m_buttonAffirmative->SetLabel(_("Save"));
2427                 if (m_buttonNegative)
2428                     m_buttonNegative->SetLabel(_("Don't Save"));
2429             }
2430         }
2431
2432         // Extra space around and at the right
2433         Add(12, 24);
2434 #elif defined(__WXGTK20__)
2435         Add(0, 0, 0, wxLEFT, 9);
2436         if (m_buttonHelp)
2437             Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2438
2439         // extra whitespace between help and cancel/ok buttons
2440         Add(0, 0, 1, wxEXPAND, 0);
2441
2442         if (m_buttonNegative){
2443             Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2444         }
2445
2446         // according to HIG, in explicit apply windows the order is:
2447         // [ Help                     Apply   Cancel   OK ]
2448         if (m_buttonApply)
2449             Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2450
2451         if (m_buttonCancel){
2452             Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
2453             // Cancel or help should be default
2454             // m_buttonCancel->SetDefaultButton();
2455         }
2456
2457         if (m_buttonAffirmative)
2458             Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
2459 #elif defined(__WXMSW__)
2460         // Windows
2461
2462         // right-justify buttons
2463         Add(0, 0, 1, wxEXPAND, 0);
2464
2465         if (m_buttonAffirmative){
2466             Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
2467         }
2468
2469         if (m_buttonNegative){
2470             Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
2471         }
2472
2473         if (m_buttonCancel){
2474             Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
2475         }
2476         if (m_buttonApply)
2477             Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
2478
2479         if (m_buttonHelp)
2480             Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
2481 #else
2482         // GTK+1 and any other platform
2483
2484         // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
2485         if (m_buttonHelp)
2486             Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
2487
2488         // extra whitespace between help and cancel/ok buttons
2489         Add(0, 0, 1, wxEXPAND, 0);
2490
2491         if (m_buttonApply)
2492             Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
2493
2494         if (m_buttonAffirmative){
2495             Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
2496         }
2497
2498         if (m_buttonNegative){
2499             Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2500         }
2501
2502         if (m_buttonCancel){
2503             Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
2504             // Cancel or help should be default
2505             // m_buttonCancel->SetDefaultButton();
2506         }
2507
2508 #endif
2509 }
2510
2511 #endif // wxUSE_BUTTON