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