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