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