/[pcsx2_0.9.7]/trunk/3rdparty/wxWidgets/src/common/sizer.cpp
ViewVC logotype

Contents of /trunk/3rdparty/wxWidgets/src/common/sizer.cpp

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.22