]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
don't leave gaps around hidden columns/rows in wxFlexGridSizer (closes bug 1659872...
[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 }
107
108 // window item
109 void 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
126 wxSizerItem::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
141 void wxSizerItem::DoSetSizer(wxSizer *sizer)
142 {
143 m_kind = Item_Sizer;
144 m_sizer = sizer;
145 }
146
147 wxSizerItem::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
166 void 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
174 wxSizerItem::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
191 wxSizerItem::~wxSizerItem()
192 {
193 delete m_userData;
194 Free();
195 }
196
197 void 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
224 wxSize 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
234 wxSize 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
271 wxSize 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
292 wxSize 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
309 void 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
396 void 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
426 void 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
452 bool 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
497 void wxSizerItem::SetOption( int option )
498 {
499 SetProportion( option );
500 }
501
502 int wxSizerItem::GetOption() const
503 {
504 return GetProportion();
505 }
506 #endif // WXWIN_COMPATIBILITY_2_6
507
508
509 //---------------------------------------------------------------------------
510 // wxSizer
511 //---------------------------------------------------------------------------
512
513 wxSizer::~wxSizer()
514 {
515 WX_CLEAR_LIST(wxSizerItemList, m_children);
516 }
517
518 wxSizerItem* 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
528 void 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
552 bool wxSizer::Remove( wxWindow *window )
553 {
554 return Detach( window );
555 }
556 #endif // WXWIN_COMPATIBILITY_2_6
557
558 bool 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
580 bool 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
596 bool 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
618 bool 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
639 bool 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
659 bool 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
687 bool 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
714 bool 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
730 void 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
751 void 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
763 wxSize 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
802 void 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
813 void 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
823 void 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
836 void 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
849 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
850 {
851 return window->GetMaxSize();
852 }
853
854 wxSize 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
867 wxSize 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
883 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
884 {
885 return GetMinSize(); // Already returns client size.
886 }
887
888 wxSize 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
903 void 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
912 wxSize 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
920 void wxSizer::DoSetMinSize( int width, int height )
921 {
922 m_minSize.x = width;
923 m_minSize.y = height;
924 }
925
926 bool 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
964 bool 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
1002 bool 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
1024 wxSizerItem* 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
1050 wxSizerItem* 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
1076 wxSizerItem* 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
1085 bool 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
1098 bool 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
1111 bool 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
1124 void 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
1134 bool 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
1153 bool 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
1172 bool 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
1186 wxGridSizer::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
1194 wxGridSizer::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
1202 int 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
1228 void 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
1261 wxSize 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
1287 void 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
1325 wxFlexGridSizer::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
1332 wxFlexGridSizer::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
1339 wxFlexGridSizer::~wxFlexGridSizer()
1340 {
1341 }
1342
1343 void wxFlexGridSizer::RecalcSizes()
1344 {
1345 int nitems, nrows, ncols;
1346 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1347 return;
1348
1349 wxPoint pt( GetPosition() );
1350 wxSize sz( GetSize() );
1351
1352 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
1353
1354 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1355
1356 int x = pt.x;
1357 for (int c = 0; c < ncols; c++)
1358 {
1359 int y = pt.y;
1360 for (int r = 0; r < nrows; r++)
1361 {
1362 int i = r * ncols + c;
1363 if (i < nitems)
1364 {
1365 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1366
1367 wxASSERT_MSG( node, _T("Failed to find node") );
1368
1369 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1370 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1371
1372 SetItemBounds( node->GetData(), x, y, w, h);
1373 }
1374 if (m_rowHeights[r] != -1)
1375 y = y + m_rowHeights[r] + m_vgap;
1376 }
1377 if (m_colWidths[c] != -1)
1378 x = x + m_colWidths[c] + m_hgap;
1379 }
1380 }
1381
1382 wxSize wxFlexGridSizer::CalcMin()
1383 {
1384 int nrows,
1385 ncols;
1386 size_t i, s;
1387
1388 // Number of rows/columns can change as items are added or removed.
1389 if ( !CalcRowsCols(nrows, ncols) )
1390 return wxSize();
1391
1392 m_rowHeights.SetCount(nrows);
1393 m_colWidths.SetCount(ncols);
1394
1395 // We have to recalcuate the sizes in case the item minimum size has
1396 // changed since the previous layout, or the item has been hidden using
1397 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1398 // dimension of the row/column will be -1, indicating that the column
1399 // itself is hidden.
1400 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1401 m_rowHeights[ i ] = -1;
1402 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1403 m_colWidths[ i ] = -1;
1404
1405 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1406
1407 i = 0;
1408 while (node)
1409 {
1410 wxSizerItem *item = node->GetData();
1411 if ( item->IsShown() )
1412 {
1413 wxSize sz( item->CalcMin() );
1414 int row = i / ncols;
1415 int col = i % ncols;
1416
1417 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1418 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1419 }
1420
1421 node = node->GetNext();
1422 i++;
1423 }
1424
1425 AdjustForFlexDirection();
1426
1427 // Sum total minimum size, including gaps between rows/columns.
1428 // -1 is used as a magic number meaning empty column.
1429 int width = 0;
1430 for (int col = 0; col < ncols; col++)
1431 if ( m_colWidths[ col ] != -1 )
1432 width += m_colWidths[ col ] + m_hgap;
1433 if (width > 0)
1434 width -= m_hgap;
1435
1436 int height = 0;
1437 for (int row = 0; row < nrows; row++)
1438 if ( m_rowHeights[ row ] != -1 )
1439 height += m_rowHeights[ row ] + m_vgap;
1440 if (height > 0)
1441 height -= m_vgap;
1442
1443 m_calculatedMinSize = wxSize( width, height );
1444 return m_calculatedMinSize;
1445 }
1446
1447 void wxFlexGridSizer::AdjustForFlexDirection()
1448 {
1449 // the logic in CalcMin works when we resize flexibly in both directions
1450 // but maybe this is not the case
1451 if ( m_flexDirection != wxBOTH )
1452 {
1453 // select the array corresponding to the direction in which we do *not*
1454 // resize flexibly
1455 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1456 : m_rowHeights;
1457
1458 const size_t count = array.GetCount();
1459
1460 // find the largest value in this array
1461 size_t n;
1462 int largest = 0;
1463
1464 for ( n = 0; n < count; ++n )
1465 {
1466 if ( array[n] > largest )
1467 largest = array[n];
1468 }
1469
1470 // and now fill it with the largest value
1471 for ( n = 0; n < count; ++n )
1472 {
1473 // don't touch hidden rows
1474 if ( array[n] != -1 )
1475 array[n] = largest;
1476 }
1477 }
1478 }
1479
1480
1481 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1482 int nrows, int ncols)
1483 {
1484 // what to do with the rows? by default, resize them proportionally
1485 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1486 {
1487 int sum_proportions = 0;
1488 int growable_space = 0;
1489 int num = 0;
1490 size_t idx;
1491 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1492 {
1493 // Since the number of rows/columns can change as items are
1494 // inserted/deleted, we need to verify at runtime that the
1495 // requested growable rows/columns are still valid.
1496 if (m_growableRows[idx] >= nrows)
1497 continue;
1498
1499 // If all items in a row/column are hidden, that row/column will
1500 // have a dimension of -1. This causes the row/column to be
1501 // hidden completely.
1502 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1503 continue;
1504 sum_proportions += m_growableRowsProportions[idx];
1505 growable_space += m_rowHeights[ m_growableRows[idx] ];
1506 num++;
1507 }
1508
1509 if (num > 0)
1510 {
1511 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1512 {
1513 if (m_growableRows[idx] >= nrows )
1514 continue;
1515 if (m_rowHeights[ m_growableRows[idx] ] != -1)
1516 {
1517 int delta = (sz.y - minsz.y);
1518 if (sum_proportions == 0)
1519 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1520 else
1521 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1522 m_rowHeights[ m_growableRows[idx] ] = delta;
1523 }
1524 }
1525 }
1526 }
1527 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1528 {
1529 // rounding problem?
1530 for ( int row = 0; row < nrows; ++row )
1531 m_rowHeights[ row ] = sz.y / nrows;
1532 }
1533
1534 // the same logic as above but for the columns
1535 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1536 {
1537 int sum_proportions = 0;
1538 int growable_space = 0;
1539 int num = 0;
1540 size_t idx;
1541 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1542 {
1543 // Since the number of rows/columns can change as items are
1544 // inserted/deleted, we need to verify at runtime that the
1545 // requested growable rows/columns are still valid.
1546 if (m_growableCols[idx] >= ncols)
1547 continue;
1548
1549 // If all items in a row/column are hidden, that row/column will
1550 // have a dimension of -1. This causes the column to be hidden
1551 // completely.
1552 if (m_colWidths[ m_growableCols[idx] ] == -1)
1553 continue;
1554 sum_proportions += m_growableColsProportions[idx];
1555 growable_space += m_colWidths[ m_growableCols[idx] ];
1556 num++;
1557 }
1558
1559 if (num > 0)
1560 {
1561 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1562 {
1563 if (m_growableCols[idx] >= ncols )
1564 continue;
1565 if (m_colWidths[ m_growableCols[idx] ] != -1)
1566 {
1567 int delta = (sz.x - minsz.x);
1568 if (sum_proportions == 0)
1569 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1570 else
1571 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1572 m_colWidths[ m_growableCols[idx] ] = delta;
1573 }
1574 }
1575 }
1576 }
1577 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1578 {
1579 for ( int col=0; col < ncols; ++col )
1580 m_colWidths[ col ] = sz.x / ncols;
1581 }
1582 }
1583
1584
1585 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1586 {
1587 m_growableRows.Add( idx );
1588 m_growableRowsProportions.Add( proportion );
1589 }
1590
1591 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1592 {
1593 m_growableCols.Add( idx );
1594 m_growableColsProportions.Add( proportion );
1595 }
1596
1597 // helper function for RemoveGrowableCol/Row()
1598 static void
1599 DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1600 {
1601 const size_t count = items.size();
1602 for ( size_t n = 0; n < count; n++ )
1603 {
1604 if ( (size_t)items[n] == idx )
1605 {
1606 items.RemoveAt(n);
1607 proportions.RemoveAt(n);
1608 return;
1609 }
1610 }
1611
1612 wxFAIL_MSG( _T("column/row is already not growable") );
1613 }
1614
1615 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1616 {
1617 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1618 }
1619
1620 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1621 {
1622 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
1623 }
1624
1625 //---------------------------------------------------------------------------
1626 // wxBoxSizer
1627 //---------------------------------------------------------------------------
1628
1629 void wxBoxSizer::RecalcSizes()
1630 {
1631 if ( m_children.empty() )
1632 return;
1633
1634 // the amount of free space which we should redistribute among the
1635 // stretchable items (i.e. those with non zero proportion)
1636 const int delta = SizeInMajorDir(m_size) - SizeInMajorDir(m_minSize);
1637
1638 // the position at which we put the next child
1639 wxPoint pt(m_position);
1640
1641 const wxCoord totalMinorSize = SizeInMinorDir(m_size);
1642
1643 for ( wxSizerItemList::const_iterator i = m_children.begin();
1644 i != m_children.end();
1645 ++i )
1646 {
1647 wxSizerItem * const item = *i;
1648
1649 if ( !item->IsShown() )
1650 continue;
1651
1652 const wxSize sizeThis(item->GetMinSizeWithBorder());
1653
1654
1655 // adjust the size in the major direction using the proportion
1656 wxCoord majorSize = SizeInMajorDir(sizeThis);
1657 if ( item->GetProportion() )
1658 {
1659 // as at least one visible item has non-zero proportion the total
1660 // proportion must be non zero
1661 majorSize += (delta * item->GetProportion()) / m_totalProportion;
1662 }
1663
1664
1665 // apply the alignment in the minor direction
1666 wxPoint posChild(pt);
1667
1668 wxCoord minorSize = SizeInMinorDir(sizeThis);
1669 const int flag = item->GetFlag();
1670 if ( flag & (wxEXPAND | wxSHAPED) )
1671 {
1672 minorSize = totalMinorSize;
1673 }
1674 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1675 {
1676 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1677 }
1678 // NB: wxCENTRE is used here only for backwards compatibility,
1679 // wxALIGN_CENTRE should be used in new code
1680 else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1681 {
1682 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1683 }
1684
1685
1686 // apply RTL adjustment for horizontal sizers:
1687 if ( !IsVertical() && m_containingWindow )
1688 {
1689 posChild.x = m_containingWindow->AdjustForLayoutDirection
1690 (
1691 posChild.x,
1692 majorSize,
1693 m_size.x
1694 );
1695 }
1696
1697 // finally set size of this child and advance to the next one
1698 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1699
1700 PosInMajorDir(pt) += majorSize;
1701 }
1702 }
1703
1704 wxSize wxBoxSizer::CalcMin()
1705 {
1706 m_totalProportion = 0;
1707 m_minSize = wxSize(0, 0);
1708
1709 // calculate the minimal sizes for all items and count sum of proportions
1710 for ( wxSizerItemList::const_iterator i = m_children.begin();
1711 i != m_children.end();
1712 ++i )
1713 {
1714 wxSizerItem * const item = *i;
1715
1716 if ( !item->IsShown() )
1717 continue;
1718
1719 const wxSize sizeMinThis = item->CalcMin();
1720
1721 SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
1722 if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
1723 SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
1724
1725 m_totalProportion += item->GetProportion();
1726 }
1727
1728 return m_minSize;
1729 }
1730
1731 //---------------------------------------------------------------------------
1732 // wxStaticBoxSizer
1733 //---------------------------------------------------------------------------
1734
1735 #if wxUSE_STATBOX
1736
1737 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1738 : wxBoxSizer( orient ),
1739 m_staticBox( box )
1740 {
1741 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1742
1743 // do this so that our Detach() is called if the static box is destroyed
1744 // before we are
1745 m_staticBox->SetContainingSizer(this);
1746 }
1747
1748 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1749 : wxBoxSizer(orient),
1750 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1751 {
1752 // same as above
1753 m_staticBox->SetContainingSizer(this);
1754 }
1755
1756 wxStaticBoxSizer::~wxStaticBoxSizer()
1757 {
1758 delete m_staticBox;
1759 }
1760
1761 static void GetStaticBoxBorders( wxStaticBox *box,
1762 int *borderTop,
1763 int *borderOther)
1764 {
1765 // this has to be done platform by platform as there is no way to
1766 // guess the thickness of a wxStaticBox border
1767 box->GetBordersForSizer(borderTop, borderOther);
1768 }
1769
1770 void wxStaticBoxSizer::RecalcSizes()
1771 {
1772 int top_border, other_border;
1773 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1774
1775 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1776
1777 wxPoint old_pos( m_position );
1778 m_position.x += other_border;
1779 m_position.y += top_border;
1780 wxSize old_size( m_size );
1781 m_size.x -= 2*other_border;
1782 m_size.y -= top_border + other_border;
1783
1784 wxBoxSizer::RecalcSizes();
1785
1786 m_position = old_pos;
1787 m_size = old_size;
1788 }
1789
1790 wxSize wxStaticBoxSizer::CalcMin()
1791 {
1792 int top_border, other_border;
1793 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1794
1795 wxSize ret( wxBoxSizer::CalcMin() );
1796 ret.x += 2*other_border;
1797 ret.y += other_border + top_border;
1798
1799 return ret;
1800 }
1801
1802 void wxStaticBoxSizer::ShowItems( bool show )
1803 {
1804 m_staticBox->Show( show );
1805 wxBoxSizer::ShowItems( show );
1806 }
1807
1808 bool wxStaticBoxSizer::Detach( wxWindow *window )
1809 {
1810 // avoid deleting m_staticBox in our dtor if it's being detached from the
1811 // sizer (which can happen because it's being already destroyed for
1812 // example)
1813 if ( window == m_staticBox )
1814 {
1815 m_staticBox = NULL;
1816 return true;
1817 }
1818
1819 return wxSizer::Detach( window );
1820 }
1821
1822 #endif // wxUSE_STATBOX
1823
1824 #if wxUSE_BUTTON
1825
1826 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1827 : wxBoxSizer(wxHORIZONTAL)
1828 {
1829 // Vertical buttons with lots of space on either side
1830 // looks rubbish on WinCE, so let's not do this for now.
1831 // If we are going to use vertical buttons, we should
1832 // put the sizer to the right of other controls in the dialog,
1833 // and that's beyond the scope of this sizer.
1834 #ifndef __WXWINCE__
1835 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1836 // If we have a PDA screen, put yes/no button over
1837 // all other buttons, otherwise on the left side.
1838 if (is_pda)
1839 m_orient = wxVERTICAL;
1840 #endif
1841
1842 m_buttonAffirmative = NULL;
1843 m_buttonApply = NULL;
1844 m_buttonNegative = NULL;
1845 m_buttonCancel = NULL;
1846 m_buttonHelp = NULL;
1847 }
1848
1849 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1850 {
1851 switch (mybutton->GetId())
1852 {
1853 case wxID_OK:
1854 case wxID_YES:
1855 case wxID_SAVE:
1856 m_buttonAffirmative = mybutton;
1857 break;
1858 case wxID_APPLY:
1859 m_buttonApply = mybutton;
1860 break;
1861 case wxID_NO:
1862 m_buttonNegative = mybutton;
1863 break;
1864 case wxID_CANCEL:
1865 case wxID_CLOSE:
1866 m_buttonCancel = mybutton;
1867 break;
1868 case wxID_HELP:
1869 case wxID_CONTEXT_HELP:
1870 m_buttonHelp = mybutton;
1871 break;
1872 default:
1873 break;
1874 }
1875 }
1876
1877 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1878 {
1879 m_buttonAffirmative = button;
1880 }
1881
1882 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1883 {
1884 m_buttonNegative = button;
1885 }
1886
1887 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1888 {
1889 m_buttonCancel = button;
1890 }
1891
1892 void wxStdDialogButtonSizer::Realize()
1893 {
1894 #ifdef __WXMAC__
1895 Add(0, 0, 0, wxLEFT, 6);
1896 if (m_buttonHelp)
1897 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1898
1899 if (m_buttonNegative){
1900 // HIG POLICE BULLETIN - destructive buttons need extra padding
1901 // 24 pixels on either side
1902 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1903 }
1904
1905 // extra whitespace between help/negative and cancel/ok buttons
1906 Add(0, 0, 1, wxEXPAND, 0);
1907
1908 if (m_buttonCancel){
1909 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1910 // Cancel or help should be default
1911 // m_buttonCancel->SetDefaultButton();
1912 }
1913
1914 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1915 // figure the best place is between Cancel and OK
1916 if (m_buttonApply)
1917 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1918
1919 if (m_buttonAffirmative){
1920 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1921
1922 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1923 // these buttons have set labels under Mac so we should use them
1924 m_buttonAffirmative->SetLabel(_("Save"));
1925 if (m_buttonNegative)
1926 m_buttonNegative->SetLabel(_("Don't Save"));
1927 }
1928 }
1929
1930 // Extra space around and at the right
1931 Add(12, 24);
1932 #elif defined(__WXGTK20__)
1933 Add(0, 0, 0, wxLEFT, 9);
1934 if (m_buttonHelp)
1935 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1936
1937 // extra whitespace between help and cancel/ok buttons
1938 Add(0, 0, 1, wxEXPAND, 0);
1939
1940 if (m_buttonNegative){
1941 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1942 }
1943
1944 // according to HIG, in explicit apply windows the order is:
1945 // [ Help Apply Cancel OK ]
1946 if (m_buttonApply)
1947 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1948
1949 if (m_buttonCancel){
1950 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1951 // Cancel or help should be default
1952 // m_buttonCancel->SetDefaultButton();
1953 }
1954
1955 if (m_buttonAffirmative)
1956 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1957 #elif defined(__WXMSW__)
1958 // Windows
1959
1960 // right-justify buttons
1961 Add(0, 0, 1, wxEXPAND, 0);
1962
1963 if (m_buttonAffirmative){
1964 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
1965 }
1966
1967 if (m_buttonNegative){
1968 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
1969 }
1970
1971 if (m_buttonCancel){
1972 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
1973 }
1974 if (m_buttonApply)
1975 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
1976
1977 if (m_buttonHelp)
1978 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
1979 #else
1980 // GTK+1 and any other platform
1981
1982 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
1983 if (m_buttonHelp)
1984 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1985
1986 // extra whitespace between help and cancel/ok buttons
1987 Add(0, 0, 1, wxEXPAND, 0);
1988
1989 if (m_buttonApply)
1990 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1991
1992 if (m_buttonAffirmative){
1993 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1994 }
1995
1996 if (m_buttonNegative){
1997 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1998 }
1999
2000 if (m_buttonCancel){
2001 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
2002 // Cancel or help should be default
2003 // m_buttonCancel->SetDefaultButton();
2004 }
2005
2006 #endif
2007 }
2008
2009 #endif // wxUSE_BUTTON