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