]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
af09c05b3e34a2c57ccd35813e951f4ceaa0bdbc
[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 array[n] = largest;
1474 }
1475 }
1476 }
1477
1478
1479 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1480 int nrows, int ncols)
1481 {
1482 // what to do with the rows? by default, resize them proportionally
1483 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1484 {
1485 int sum_proportions = 0;
1486 int growable_space = 0;
1487 int num = 0;
1488 size_t idx;
1489 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1490 {
1491 // Since the number of rows/columns can change as items are
1492 // inserted/deleted, we need to verify at runtime that the
1493 // requested growable rows/columns are still valid.
1494 if (m_growableRows[idx] >= nrows)
1495 continue;
1496
1497 // If all items in a row/column are hidden, that row/column will
1498 // have a dimension of -1. This causes the row/column to be
1499 // hidden completely.
1500 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1501 continue;
1502 sum_proportions += m_growableRowsProportions[idx];
1503 growable_space += m_rowHeights[ m_growableRows[idx] ];
1504 num++;
1505 }
1506
1507 if (num > 0)
1508 {
1509 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1510 {
1511 if (m_growableRows[idx] >= nrows )
1512 continue;
1513 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1514 m_rowHeights[ m_growableRows[idx] ] = 0;
1515 else
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 m_colWidths[ m_growableCols[idx] ] = 0;
1567 else
1568 {
1569 int delta = (sz.x - minsz.x);
1570 if (sum_proportions == 0)
1571 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1572 else
1573 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1574 m_colWidths[ m_growableCols[idx] ] = delta;
1575 }
1576 }
1577 }
1578 }
1579 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1580 {
1581 for ( int col=0; col < ncols; ++col )
1582 m_colWidths[ col ] = sz.x / ncols;
1583 }
1584 }
1585
1586
1587 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1588 {
1589 m_growableRows.Add( idx );
1590 m_growableRowsProportions.Add( proportion );
1591 }
1592
1593 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1594 {
1595 m_growableCols.Add( idx );
1596 m_growableColsProportions.Add( proportion );
1597 }
1598
1599 // helper function for RemoveGrowableCol/Row()
1600 static void
1601 DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions)
1602 {
1603 const size_t count = items.size();
1604 for ( size_t n = 0; n < count; n++ )
1605 {
1606 if ( (size_t)items[n] == idx )
1607 {
1608 items.RemoveAt(n);
1609 proportions.RemoveAt(n);
1610 return;
1611 }
1612 }
1613
1614 wxFAIL_MSG( _T("column/row is already not growable") );
1615 }
1616
1617 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1618 {
1619 DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions);
1620 }
1621
1622 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1623 {
1624 DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions);
1625 }
1626
1627 //---------------------------------------------------------------------------
1628 // wxBoxSizer
1629 //---------------------------------------------------------------------------
1630
1631 void wxBoxSizer::RecalcSizes()
1632 {
1633 if ( m_children.empty() )
1634 return;
1635
1636 // the amount of free space which we should redistribute among the
1637 // stretchable items (i.e. those with non zero proportion)
1638 const int delta = SizeInMajorDir(m_size) - SizeInMajorDir(m_minSize);
1639
1640 // the position at which we put the next child
1641 wxPoint pt(m_position);
1642
1643 const wxCoord totalMinorSize = SizeInMinorDir(m_size);
1644
1645 for ( wxSizerItemList::const_iterator i = m_children.begin();
1646 i != m_children.end();
1647 ++i )
1648 {
1649 wxSizerItem * const item = *i;
1650
1651 if ( !item->IsShown() )
1652 continue;
1653
1654 const wxSize sizeThis(item->GetMinSizeWithBorder());
1655
1656
1657 // adjust the size in the major direction using the proportion
1658 wxCoord majorSize = SizeInMajorDir(sizeThis);
1659 if ( item->GetProportion() )
1660 {
1661 // as at least one visible item has non-zero proportion the total
1662 // proportion must be non zero
1663 majorSize += (delta * item->GetProportion()) / m_totalProportion;
1664 }
1665
1666
1667 // apply the alignment in the minor direction
1668 wxPoint posChild(pt);
1669
1670 wxCoord minorSize = SizeInMinorDir(sizeThis);
1671 const int flag = item->GetFlag();
1672 if ( flag & (wxEXPAND | wxSHAPED) )
1673 {
1674 minorSize = totalMinorSize;
1675 }
1676 else if ( flag & (IsVertical() ? wxALIGN_RIGHT : wxALIGN_BOTTOM) )
1677 {
1678 PosInMinorDir(posChild) += totalMinorSize - minorSize;
1679 }
1680 // NB: wxCENTRE is used here only for backwards compatibility,
1681 // wxALIGN_CENTRE should be used in new code
1682 else if ( flag & (wxCENTER | wxALIGN_CENTRE) )
1683 {
1684 PosInMinorDir(posChild) += (totalMinorSize - minorSize) / 2;
1685 }
1686
1687
1688 // apply RTL adjustment for horizontal sizers:
1689 if ( !IsVertical() && m_containingWindow )
1690 {
1691 posChild.x = m_containingWindow->AdjustForLayoutDirection
1692 (
1693 posChild.x,
1694 majorSize,
1695 m_size.x
1696 );
1697 }
1698
1699 // finally set size of this child and advance to the next one
1700 item->SetDimension(posChild, SizeFromMajorMinor(majorSize, minorSize));
1701
1702 PosInMajorDir(pt) += majorSize;
1703 }
1704 }
1705
1706 wxSize wxBoxSizer::CalcMin()
1707 {
1708 m_totalProportion = 0;
1709 m_minSize = wxSize(0, 0);
1710
1711 // calculate the minimal sizes for all items and count sum of proportions
1712 for ( wxSizerItemList::const_iterator i = m_children.begin();
1713 i != m_children.end();
1714 ++i )
1715 {
1716 wxSizerItem * const item = *i;
1717
1718 if ( !item->IsShown() )
1719 continue;
1720
1721 const wxSize sizeMinThis = item->CalcMin();
1722
1723 SizeInMajorDir(m_minSize) += SizeInMajorDir(sizeMinThis);
1724 if ( SizeInMinorDir(sizeMinThis) > SizeInMinorDir(m_minSize) )
1725 SizeInMinorDir(m_minSize) = SizeInMinorDir(sizeMinThis);
1726
1727 m_totalProportion += item->GetProportion();
1728 }
1729
1730 return m_minSize;
1731 }
1732
1733 //---------------------------------------------------------------------------
1734 // wxStaticBoxSizer
1735 //---------------------------------------------------------------------------
1736
1737 #if wxUSE_STATBOX
1738
1739 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1740 : wxBoxSizer( orient ),
1741 m_staticBox( box )
1742 {
1743 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1744
1745 // do this so that our Detach() is called if the static box is destroyed
1746 // before we are
1747 m_staticBox->SetContainingSizer(this);
1748 }
1749
1750 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1751 : wxBoxSizer(orient),
1752 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1753 {
1754 // same as above
1755 m_staticBox->SetContainingSizer(this);
1756 }
1757
1758 wxStaticBoxSizer::~wxStaticBoxSizer()
1759 {
1760 delete m_staticBox;
1761 }
1762
1763 static void GetStaticBoxBorders( wxStaticBox *box,
1764 int *borderTop,
1765 int *borderOther)
1766 {
1767 // this has to be done platform by platform as there is no way to
1768 // guess the thickness of a wxStaticBox border
1769 box->GetBordersForSizer(borderTop, borderOther);
1770 }
1771
1772 void wxStaticBoxSizer::RecalcSizes()
1773 {
1774 int top_border, other_border;
1775 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1776
1777 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1778
1779 wxPoint old_pos( m_position );
1780 m_position.x += other_border;
1781 m_position.y += top_border;
1782 wxSize old_size( m_size );
1783 m_size.x -= 2*other_border;
1784 m_size.y -= top_border + other_border;
1785
1786 wxBoxSizer::RecalcSizes();
1787
1788 m_position = old_pos;
1789 m_size = old_size;
1790 }
1791
1792 wxSize wxStaticBoxSizer::CalcMin()
1793 {
1794 int top_border, other_border;
1795 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1796
1797 wxSize ret( wxBoxSizer::CalcMin() );
1798 ret.x += 2*other_border;
1799 ret.y += other_border + top_border;
1800
1801 return ret;
1802 }
1803
1804 void wxStaticBoxSizer::ShowItems( bool show )
1805 {
1806 m_staticBox->Show( show );
1807 wxBoxSizer::ShowItems( show );
1808 }
1809
1810 bool wxStaticBoxSizer::Detach( wxWindow *window )
1811 {
1812 // avoid deleting m_staticBox in our dtor if it's being detached from the
1813 // sizer (which can happen because it's being already destroyed for
1814 // example)
1815 if ( window == m_staticBox )
1816 {
1817 m_staticBox = NULL;
1818 return true;
1819 }
1820
1821 return wxSizer::Detach( window );
1822 }
1823
1824 #endif // wxUSE_STATBOX
1825
1826 #if wxUSE_BUTTON
1827
1828 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1829 : wxBoxSizer(wxHORIZONTAL)
1830 {
1831 // Vertical buttons with lots of space on either side
1832 // looks rubbish on WinCE, so let's not do this for now.
1833 // If we are going to use vertical buttons, we should
1834 // put the sizer to the right of other controls in the dialog,
1835 // and that's beyond the scope of this sizer.
1836 #ifndef __WXWINCE__
1837 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1838 // If we have a PDA screen, put yes/no button over
1839 // all other buttons, otherwise on the left side.
1840 if (is_pda)
1841 m_orient = wxVERTICAL;
1842 #endif
1843
1844 m_buttonAffirmative = NULL;
1845 m_buttonApply = NULL;
1846 m_buttonNegative = NULL;
1847 m_buttonCancel = NULL;
1848 m_buttonHelp = NULL;
1849 }
1850
1851 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1852 {
1853 switch (mybutton->GetId())
1854 {
1855 case wxID_OK:
1856 case wxID_YES:
1857 case wxID_SAVE:
1858 m_buttonAffirmative = mybutton;
1859 break;
1860 case wxID_APPLY:
1861 m_buttonApply = mybutton;
1862 break;
1863 case wxID_NO:
1864 m_buttonNegative = mybutton;
1865 break;
1866 case wxID_CANCEL:
1867 case wxID_CLOSE:
1868 m_buttonCancel = mybutton;
1869 break;
1870 case wxID_HELP:
1871 case wxID_CONTEXT_HELP:
1872 m_buttonHelp = mybutton;
1873 break;
1874 default:
1875 break;
1876 }
1877 }
1878
1879 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1880 {
1881 m_buttonAffirmative = button;
1882 }
1883
1884 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1885 {
1886 m_buttonNegative = button;
1887 }
1888
1889 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1890 {
1891 m_buttonCancel = button;
1892 }
1893
1894 void wxStdDialogButtonSizer::Realize()
1895 {
1896 #ifdef __WXMAC__
1897 Add(0, 0, 0, wxLEFT, 6);
1898 if (m_buttonHelp)
1899 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1900
1901 if (m_buttonNegative){
1902 // HIG POLICE BULLETIN - destructive buttons need extra padding
1903 // 24 pixels on either side
1904 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1905 }
1906
1907 // extra whitespace between help/negative and cancel/ok buttons
1908 Add(0, 0, 1, wxEXPAND, 0);
1909
1910 if (m_buttonCancel){
1911 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1912 // Cancel or help should be default
1913 // m_buttonCancel->SetDefaultButton();
1914 }
1915
1916 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1917 // figure the best place is between Cancel and OK
1918 if (m_buttonApply)
1919 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1920
1921 if (m_buttonAffirmative){
1922 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1923
1924 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1925 // these buttons have set labels under Mac so we should use them
1926 m_buttonAffirmative->SetLabel(_("Save"));
1927 if (m_buttonNegative)
1928 m_buttonNegative->SetLabel(_("Don't Save"));
1929 }
1930 }
1931
1932 // Extra space around and at the right
1933 Add(12, 24);
1934 #elif defined(__WXGTK20__)
1935 Add(0, 0, 0, wxLEFT, 9);
1936 if (m_buttonHelp)
1937 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1938
1939 // extra whitespace between help and cancel/ok buttons
1940 Add(0, 0, 1, wxEXPAND, 0);
1941
1942 if (m_buttonNegative){
1943 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1944 }
1945
1946 // according to HIG, in explicit apply windows the order is:
1947 // [ Help Apply Cancel OK ]
1948 if (m_buttonApply)
1949 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1950
1951 if (m_buttonCancel){
1952 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1953 // Cancel or help should be default
1954 // m_buttonCancel->SetDefaultButton();
1955 }
1956
1957 if (m_buttonAffirmative)
1958 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1959 #elif defined(__WXMSW__)
1960 // Windows
1961
1962 // right-justify buttons
1963 Add(0, 0, 1, wxEXPAND, 0);
1964
1965 if (m_buttonAffirmative){
1966 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
1967 }
1968
1969 if (m_buttonNegative){
1970 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
1971 }
1972
1973 if (m_buttonCancel){
1974 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
1975 }
1976 if (m_buttonApply)
1977 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
1978
1979 if (m_buttonHelp)
1980 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
1981 #else
1982 // GTK+1 and any other platform
1983
1984 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
1985 if (m_buttonHelp)
1986 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1987
1988 // extra whitespace between help and cancel/ok buttons
1989 Add(0, 0, 1, wxEXPAND, 0);
1990
1991 if (m_buttonApply)
1992 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1993
1994 if (m_buttonAffirmative){
1995 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1996 }
1997
1998 if (m_buttonNegative){
1999 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
2000 }
2001
2002 if (m_buttonCancel){
2003 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
2004 // Cancel or help should be default
2005 // m_buttonCancel->SetDefaultButton();
2006 }
2007
2008 #endif
2009 }
2010
2011 #endif // wxUSE_BUTTON