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