]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
Removed WXWIN_COMPATIBILITY_2_2 together with code guarded by it.
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: 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 #endif // WX_PRECOMP
25
26 #include "wx/sizer.h"
27 #include "wx/utils.h"
28 #include "wx/statbox.h"
29 #include "wx/settings.h"
30 #include "wx/listimpl.cpp"
31 #include "wx/intl.h"
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 return m_sizer->IsShown();
451
452 case Item_Spacer:
453 return m_spacer->IsShown();
454
455 case Item_Max:
456 default:
457 wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") );
458 }
459
460 return false;
461 }
462
463 void wxSizerItem::SetOption( int option )
464 {
465 SetProportion( option );
466 }
467
468 int wxSizerItem::GetOption() const
469 {
470 return GetProportion();
471 }
472
473
474 //---------------------------------------------------------------------------
475 // wxSizer
476 //---------------------------------------------------------------------------
477
478 wxSizer::wxSizer()
479 {
480 m_isShown = true;
481 }
482
483 wxSizer::~wxSizer()
484 {
485 WX_CLEAR_LIST(wxSizerItemList, m_children);
486 }
487
488 wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item )
489 {
490 m_children.Insert( index, item );
491
492 if ( item->GetWindow() )
493 item->GetWindow()->SetContainingSizer( this );
494
495 return item;
496 }
497
498 bool wxSizer::Remove( wxWindow *window )
499 {
500 return Detach( window );
501 }
502
503 bool wxSizer::Remove( wxSizer *sizer )
504 {
505 wxASSERT_MSG( sizer, _T("Removing NULL sizer") );
506
507 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
508 while (node)
509 {
510 wxSizerItem *item = node->GetData();
511
512 if (item->GetSizer() == sizer)
513 {
514 delete item;
515 m_children.Erase( node );
516 return true;
517 }
518
519 node = node->GetNext();
520 }
521
522 return false;
523 }
524
525 bool wxSizer::Remove( int index )
526 {
527 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
528 false,
529 _T("Remove index is out of range") );
530
531 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
532
533 wxCHECK_MSG( node, false, _T("Failed to find child node") );
534
535 wxSizerItem *item = node->GetData();
536
537 if ( item->IsWindow() )
538 item->GetWindow()->SetContainingSizer( NULL );
539
540 delete item;
541 m_children.Erase( node );
542 return true;
543 }
544
545 bool wxSizer::Detach( wxSizer *sizer )
546 {
547 wxASSERT_MSG( sizer, _T("Detaching NULL sizer") );
548
549 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
550 while (node)
551 {
552 wxSizerItem *item = node->GetData();
553
554 if (item->GetSizer() == sizer)
555 {
556 item->DetachSizer();
557 delete item;
558 m_children.Erase( node );
559 return true;
560 }
561 node = node->GetNext();
562 }
563
564 return false;
565 }
566
567 bool wxSizer::Detach( wxWindow *window )
568 {
569 wxASSERT_MSG( window, _T("Detaching NULL window") );
570
571 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
572 while (node)
573 {
574 wxSizerItem *item = node->GetData();
575
576 if (item->GetWindow() == window)
577 {
578 item->GetWindow()->SetContainingSizer( NULL );
579 delete item;
580 m_children.Erase( node );
581 return true;
582 }
583 node = node->GetNext();
584 }
585
586 return false;
587 }
588
589 bool wxSizer::Detach( int index )
590 {
591 wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(),
592 false,
593 _T("Detach index is out of range") );
594
595 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
596
597 wxCHECK_MSG( node, false, _T("Failed to find child node") );
598
599 wxSizerItem *item = node->GetData();
600
601 if ( item->IsSizer() )
602 item->DetachSizer();
603 else if ( item->IsWindow() )
604 item->GetWindow()->SetContainingSizer( NULL );
605
606 delete item;
607 m_children.Erase( node );
608 return true;
609 }
610
611 void wxSizer::Clear( bool delete_windows )
612 {
613 // First clear the ContainingSizer pointers
614 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
615 while (node)
616 {
617 wxSizerItem *item = node->GetData();
618
619 if (item->IsWindow())
620 item->GetWindow()->SetContainingSizer( NULL );
621 node = node->GetNext();
622 }
623
624 // Destroy the windows if needed
625 if (delete_windows)
626 DeleteWindows();
627
628 // Now empty the list
629 WX_CLEAR_LIST(wxSizerItemList, m_children);
630 }
631
632 void wxSizer::DeleteWindows()
633 {
634 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
635 while (node)
636 {
637 wxSizerItem *item = node->GetData();
638
639 item->DeleteWindows();
640 node = node->GetNext();
641 }
642 }
643
644 wxSize wxSizer::Fit( wxWindow *window )
645 {
646 wxSize size(window->IsTopLevel() ? FitSize(window)
647 : GetMinWindowSize(window));
648
649 window->SetSize( size );
650
651 return size;
652 }
653
654 void wxSizer::FitInside( wxWindow *window )
655 {
656 wxSize size;
657 if (window->IsTopLevel())
658 size = VirtualFitSize( window );
659 else
660 size = GetMinClientSize( window );
661
662 window->SetVirtualSize( size );
663 }
664
665 void wxSizer::Layout()
666 {
667 // (re)calculates minimums needed for each item and other preparations
668 // for layout
669 CalcMin();
670
671 // Applies the layout and repositions/resizes the items
672 RecalcSizes();
673 }
674
675 void wxSizer::SetSizeHints( wxWindow *window )
676 {
677 // Preserve the window's max size hints, but set the
678 // lower bound according to the sizer calculations.
679
680 wxSize size = Fit( window );
681
682 window->SetSizeHints( size.x,
683 size.y,
684 window->GetMaxWidth(),
685 window->GetMaxHeight() );
686 }
687
688 void wxSizer::SetVirtualSizeHints( wxWindow *window )
689 {
690 // Preserve the window's max size hints, but set the
691 // lower bound according to the sizer calculations.
692
693 FitInside( window );
694 wxSize size( window->GetVirtualSize() );
695 window->SetVirtualSizeHints( size.x,
696 size.y,
697 window->GetMaxWidth(),
698 window->GetMaxHeight() );
699 }
700
701 wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const
702 {
703 return window->GetMaxSize();
704 }
705
706 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
707 {
708 wxSize minSize( GetMinSize() );
709 wxSize size( window->GetSize() );
710 wxSize client_size( window->GetClientSize() );
711
712 return wxSize( minSize.x+size.x-client_size.x,
713 minSize.y+size.y-client_size.y );
714 }
715
716 // TODO on mac we need a function that determines how much free space this
717 // min size contains, in order to make sure that we have 20 pixels of free
718 // space around the controls
719
720 // Return a window size that will fit within the screens dimensions
721 wxSize wxSizer::FitSize( wxWindow *window )
722 {
723 wxSize size = GetMinWindowSize( window );
724 wxSize sizeMax = GetMaxWindowSize( window );
725
726 // Limit the size if sizeMax != wxDefaultSize
727
728 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
729 size.x = sizeMax.x;
730 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
731 size.y = sizeMax.y;
732
733 return size;
734 }
735
736 wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const
737 {
738 wxSize maxSize( window->GetMaxSize() );
739
740 if ( maxSize != wxDefaultSize )
741 {
742 wxSize size( window->GetSize() );
743 wxSize client_size( window->GetClientSize() );
744
745 return wxSize( maxSize.x + client_size.x - size.x,
746 maxSize.y + client_size.y - size.y );
747 }
748 else
749 return wxDefaultSize;
750 }
751
752 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
753 {
754 return GetMinSize(); // Already returns client size.
755 }
756
757 wxSize wxSizer::VirtualFitSize( wxWindow *window )
758 {
759 wxSize size = GetMinClientSize( window );
760 wxSize sizeMax = GetMaxClientSize( window );
761
762 // Limit the size if sizeMax != wxDefaultSize
763
764 if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord )
765 size.x = sizeMax.x;
766 if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord )
767 size.y = sizeMax.y;
768
769 return size;
770 }
771
772 void wxSizer::SetDimension( int x, int y, int width, int height )
773 {
774 m_position.x = x;
775 m_position.y = y;
776 m_size.x = width;
777 m_size.y = height;
778 Layout();
779 }
780
781 wxSize wxSizer::GetMinSize()
782 {
783 wxSize ret( CalcMin() );
784 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
785 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
786 return ret;
787 }
788
789 void wxSizer::DoSetMinSize( int width, int height )
790 {
791 m_minSize.x = width;
792 m_minSize.y = height;
793 }
794
795 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
796 {
797 wxASSERT_MSG( window, _T("SetMinSize for NULL window") );
798
799 // Is it our immediate child?
800
801 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
802 while (node)
803 {
804 wxSizerItem *item = node->GetData();
805
806 if (item->GetWindow() == window)
807 {
808 item->SetMinSize( width, height );
809 return true;
810 }
811 node = node->GetNext();
812 }
813
814 // No? Search any subsizers we own then
815
816 node = m_children.GetFirst();
817 while (node)
818 {
819 wxSizerItem *item = node->GetData();
820
821 if ( item->GetSizer() &&
822 item->GetSizer()->DoSetItemMinSize( window, width, height ) )
823 {
824 // A child sizer found the requested windw, exit.
825 return true;
826 }
827 node = node->GetNext();
828 }
829
830 return false;
831 }
832
833 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
834 {
835 wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") );
836
837 // Is it our immediate child?
838
839 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
840 while (node)
841 {
842 wxSizerItem *item = node->GetData();
843
844 if (item->GetSizer() == sizer)
845 {
846 item->GetSizer()->DoSetMinSize( width, height );
847 return true;
848 }
849 node = node->GetNext();
850 }
851
852 // No? Search any subsizers we own then
853
854 node = m_children.GetFirst();
855 while (node)
856 {
857 wxSizerItem *item = node->GetData();
858
859 if ( item->GetSizer() &&
860 item->GetSizer()->DoSetItemMinSize( sizer, width, height ) )
861 {
862 // A child found the requested sizer, exit.
863 return true;
864 }
865 node = node->GetNext();
866 }
867
868 return false;
869 }
870
871 bool wxSizer::DoSetItemMinSize( size_t index, int width, int height )
872 {
873 wxSizerItemList::compatibility_iterator node = m_children.Item( index );
874
875 wxCHECK_MSG( node, false, _T("Failed to find child node") );
876
877 wxSizerItem *item = node->GetData();
878
879 if (item->GetSizer())
880 {
881 // Sizers contains the minimal size in them, if not calculated ...
882 item->GetSizer()->DoSetMinSize( width, height );
883 }
884 else
885 {
886 // ... but the minimal size of spacers and windows is stored via the item
887 item->SetMinSize( width, height );
888 }
889
890 return true;
891 }
892
893 wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive )
894 {
895 wxASSERT_MSG( window, _T("GetItem for NULL window") );
896
897 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
898 while (node)
899 {
900 wxSizerItem *item = node->GetData();
901
902 if (item->GetWindow() == window)
903 {
904 return item;
905 }
906 else if (recursive && item->IsSizer())
907 {
908 wxSizerItem *subitem = item->GetSizer()->GetItem( window, true );
909 if (subitem)
910 return subitem;
911 }
912
913 node = node->GetNext();
914 }
915
916 return NULL;
917 }
918
919 wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive )
920 {
921 wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") );
922
923 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
924 while (node)
925 {
926 wxSizerItem *item = node->GetData();
927
928 if (item->GetSizer() == sizer)
929 {
930 return item;
931 }
932 else if (recursive && item->IsSizer())
933 {
934 wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true );
935 if (subitem)
936 return subitem;
937 }
938
939 node = node->GetNext();
940 }
941
942 return NULL;
943 }
944
945 wxSizerItem* wxSizer::GetItem( size_t index )
946 {
947 wxCHECK_MSG( index < m_children.GetCount(),
948 NULL,
949 _T("GetItem index is out of range") );
950
951 return m_children.Item( index )->GetData();
952 }
953
954 bool wxSizer::Show( wxWindow *window, bool show, bool recursive )
955 {
956 wxSizerItem *item = GetItem( window, recursive );
957
958 if ( item )
959 {
960 item->Show( show );
961 return true;
962 }
963
964 return false;
965 }
966
967 bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive )
968 {
969 wxSizerItem *item = GetItem( sizer, recursive );
970
971 if ( item )
972 {
973 item->Show( show );
974 return true;
975 }
976
977 return false;
978 }
979
980 bool wxSizer::Show( size_t index, bool show)
981 {
982 wxSizerItem *item = GetItem( index );
983
984 if ( item )
985 {
986 item->Show( show );
987 return true;
988 }
989
990 return false;
991 }
992
993 void wxSizer::ShowItems( bool show )
994 {
995 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
996 while (node)
997 {
998 node->GetData()->Show( show );
999 node = node->GetNext();
1000 }
1001 }
1002
1003 bool wxSizer::IsShown( wxWindow *window ) const
1004 {
1005 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1006 while (node)
1007 {
1008 wxSizerItem *item = node->GetData();
1009
1010 if (item->GetWindow() == window)
1011 {
1012 return item->IsShown();
1013 }
1014 node = node->GetNext();
1015 }
1016
1017 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1018
1019 return false;
1020 }
1021
1022 bool wxSizer::IsShown( wxSizer *sizer ) const
1023 {
1024 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1025 while (node)
1026 {
1027 wxSizerItem *item = node->GetData();
1028
1029 if (item->GetSizer() == sizer)
1030 {
1031 return item->IsShown();
1032 }
1033 node = node->GetNext();
1034 }
1035
1036 wxFAIL_MSG( _T("IsShown failed to find sizer item") );
1037
1038 return false;
1039 }
1040
1041 bool wxSizer::IsShown( size_t index ) const
1042 {
1043 wxCHECK_MSG( index < m_children.GetCount(),
1044 false,
1045 _T("IsShown index is out of range") );
1046
1047 return m_children.Item( index )->GetData()->IsShown();
1048 }
1049
1050
1051 //---------------------------------------------------------------------------
1052 // wxGridSizer
1053 //---------------------------------------------------------------------------
1054
1055 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
1056 : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows )
1057 , m_cols( cols )
1058 , m_vgap( vgap )
1059 , m_hgap( hgap )
1060 {
1061 }
1062
1063 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
1064 : m_rows( cols == 0 ? 1 : 0 )
1065 , m_cols( cols )
1066 , m_vgap( vgap )
1067 , m_hgap( hgap )
1068 {
1069 }
1070
1071 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
1072 {
1073 int nitems = m_children.GetCount();
1074 if ( nitems)
1075 {
1076 if ( m_cols )
1077 {
1078 ncols = m_cols;
1079 nrows = (nitems + m_cols - 1) / m_cols;
1080 }
1081 else if ( m_rows )
1082 {
1083 ncols = (nitems + m_rows - 1) / m_rows;
1084 nrows = m_rows;
1085 }
1086 else // 0 columns, 0 rows?
1087 {
1088 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
1089
1090 nrows = ncols = 0;
1091 }
1092 }
1093
1094 return nitems;
1095 }
1096
1097 void wxGridSizer::RecalcSizes()
1098 {
1099 int nitems, nrows, ncols;
1100 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1101 return;
1102
1103 wxSize sz( GetSize() );
1104 wxPoint pt( GetPosition() );
1105
1106 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
1107 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
1108
1109 int x = pt.x;
1110 for (int c = 0; c < ncols; c++)
1111 {
1112 int y = pt.y;
1113 for (int r = 0; r < nrows; r++)
1114 {
1115 int i = r * ncols + c;
1116 if (i < nitems)
1117 {
1118 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1119
1120 wxASSERT_MSG( node, _T("Failed to find SizerItemList node") );
1121
1122 SetItemBounds( node->GetData(), x, y, w, h);
1123 }
1124 y = y + h + m_vgap;
1125 }
1126 x = x + w + m_hgap;
1127 }
1128 }
1129
1130 wxSize wxGridSizer::CalcMin()
1131 {
1132 int nrows, ncols;
1133 if ( CalcRowsCols(nrows, ncols) == 0 )
1134 return wxSize(10, 10);
1135
1136 // Find the max width and height for any component
1137 int w = 0;
1138 int h = 0;
1139
1140 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1141 while (node)
1142 {
1143 wxSizerItem *item = node->GetData();
1144 wxSize sz( item->CalcMin() );
1145
1146 w = wxMax( w, sz.x );
1147 h = wxMax( h, sz.y );
1148
1149 node = node->GetNext();
1150 }
1151
1152 return wxSize( ncols * w + (ncols-1) * m_hgap,
1153 nrows * h + (nrows-1) * m_vgap );
1154 }
1155
1156 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
1157 {
1158 wxPoint pt( x,y );
1159 wxSize sz( item->GetMinSizeWithBorder() );
1160 int flag = item->GetFlag();
1161
1162 if ((flag & wxEXPAND) || (flag & wxSHAPED))
1163 {
1164 sz = wxSize(w, h);
1165 }
1166 else
1167 {
1168 if (flag & wxALIGN_CENTER_HORIZONTAL)
1169 {
1170 pt.x = x + (w - sz.x) / 2;
1171 }
1172 else if (flag & wxALIGN_RIGHT)
1173 {
1174 pt.x = x + (w - sz.x);
1175 }
1176
1177 if (flag & wxALIGN_CENTER_VERTICAL)
1178 {
1179 pt.y = y + (h - sz.y) / 2;
1180 }
1181 else if (flag & wxALIGN_BOTTOM)
1182 {
1183 pt.y = y + (h - sz.y);
1184 }
1185 }
1186
1187 item->SetDimension(pt, sz);
1188 }
1189
1190 //---------------------------------------------------------------------------
1191 // wxFlexGridSizer
1192 //---------------------------------------------------------------------------
1193
1194 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
1195 : wxGridSizer( rows, cols, vgap, hgap ),
1196 m_flexDirection(wxBOTH),
1197 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1198 {
1199 }
1200
1201 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
1202 : wxGridSizer( cols, vgap, hgap ),
1203 m_flexDirection(wxBOTH),
1204 m_growMode(wxFLEX_GROWMODE_SPECIFIED)
1205 {
1206 }
1207
1208 wxFlexGridSizer::~wxFlexGridSizer()
1209 {
1210 }
1211
1212 void wxFlexGridSizer::RecalcSizes()
1213 {
1214 int nitems, nrows, ncols;
1215 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1216 return;
1217
1218 wxPoint pt( GetPosition() );
1219 wxSize sz( GetSize() );
1220
1221 AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols);
1222
1223 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
1224
1225 int x = pt.x;
1226 for (int c = 0; c < ncols; c++)
1227 {
1228 int y = pt.y;
1229 for (int r = 0; r < nrows; r++)
1230 {
1231 int i = r * ncols + c;
1232 if (i < nitems)
1233 {
1234 wxSizerItemList::compatibility_iterator node = m_children.Item( i );
1235
1236 wxASSERT_MSG( node, _T("Failed to find node") );
1237
1238 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
1239 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
1240
1241 SetItemBounds( node->GetData(), x, y, w, h);
1242 }
1243 if (m_rowHeights[r] != -1)
1244 y = y + m_rowHeights[r] + m_vgap;
1245 }
1246 if (m_colWidths[c] != -1)
1247 x = x + m_colWidths[c] + m_hgap;
1248 }
1249 }
1250
1251 wxSize wxFlexGridSizer::CalcMin()
1252 {
1253 int nrows,
1254 ncols;
1255 size_t i, s;
1256
1257 // Number of rows/columns can change as items are added or removed.
1258 if ( !CalcRowsCols(nrows, ncols) )
1259 return wxSize(10, 10);
1260
1261 m_rowHeights.SetCount(nrows);
1262 m_colWidths.SetCount(ncols);
1263
1264 // We have to recalcuate the sizes in case the item minimum size has
1265 // changed since the previous layout, or the item has been hidden using
1266 // wxSizer::Show(). If all the items in a row/column are hidden, the final
1267 // dimension of the row/column will be -1, indicating that the column
1268 // itself is hidden.
1269 for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i )
1270 m_rowHeights[ i ] = -1;
1271 for( s = m_colWidths.GetCount(), i = 0; i < s; ++i )
1272 m_colWidths[ i ] = -1;
1273
1274 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1275
1276 i = 0;
1277 while (node)
1278 {
1279 wxSizerItem *item = node->GetData();
1280 if ( item->IsShown() )
1281 {
1282 wxSize sz( item->CalcMin() );
1283 int row = i / ncols;
1284 int col = i % ncols;
1285
1286 m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] );
1287 m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] );
1288 }
1289
1290 node = node->GetNext();
1291 i++;
1292 }
1293
1294 AdjustForFlexDirection();
1295
1296 // Sum total minimum size, including gaps between rows/columns.
1297 // -1 is used as a magic number meaning empty column.
1298 int width = 0;
1299 for (int col = 0; col < ncols; col++)
1300 if ( m_colWidths[ col ] != -1 )
1301 width += m_colWidths[ col ] + m_hgap;
1302 if (width > 0)
1303 width -= m_hgap;
1304
1305 int height = 0;
1306 for (int row = 0; row < nrows; row++)
1307 if ( m_rowHeights[ row ] != -1 )
1308 height += m_rowHeights[ row ] + m_vgap;
1309 if (height > 0)
1310 height -= m_vgap;
1311
1312 m_calculatedMinSize = wxSize( width, height );
1313 return m_calculatedMinSize;
1314 }
1315
1316 void wxFlexGridSizer::AdjustForFlexDirection()
1317 {
1318 // the logic in CalcMin works when we resize flexibly in both directions
1319 // but maybe this is not the case
1320 if ( m_flexDirection != wxBOTH )
1321 {
1322 // select the array corresponding to the direction in which we do *not*
1323 // resize flexibly
1324 wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths
1325 : m_rowHeights;
1326
1327 const int count = array.GetCount();
1328
1329 // find the largest value in this array
1330 int n, largest = 0;
1331 for ( n = 0; n < count; ++n )
1332 {
1333 if ( array[n] > largest )
1334 largest = array[n];
1335 }
1336
1337 // and now fill it with the largest value
1338 for ( n = 0; n < count; ++n )
1339 {
1340 array[n] = largest;
1341 }
1342 }
1343 }
1344
1345
1346 void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz,
1347 int nrows, int ncols)
1348 {
1349 // what to do with the rows? by default, resize them proportionally
1350 if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1351 {
1352 int sum_proportions = 0;
1353 int growable_space = 0;
1354 int num = 0;
1355 size_t idx;
1356 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1357 {
1358 // Since the number of rows/columns can change as items are
1359 // inserted/deleted, we need to verify at runtime that the
1360 // requested growable rows/columns are still valid.
1361 if (m_growableRows[idx] >= nrows)
1362 continue;
1363
1364 // If all items in a row/column are hidden, that row/column will
1365 // have a dimension of -1. This causes the row/column to be
1366 // hidden completely.
1367 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1368 continue;
1369 sum_proportions += m_growableRowsProportions[idx];
1370 growable_space += m_rowHeights[ m_growableRows[idx] ];
1371 num++;
1372 }
1373
1374 if (num > 0)
1375 {
1376 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
1377 {
1378 if (m_growableRows[idx] >= nrows )
1379 continue;
1380 if (m_rowHeights[ m_growableRows[idx] ] == -1)
1381 m_rowHeights[ m_growableRows[idx] ] = 0;
1382 else
1383 {
1384 int delta = (sz.y - minsz.y);
1385 if (sum_proportions == 0)
1386 delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ];
1387 else
1388 delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions;
1389 m_rowHeights[ m_growableRows[idx] ] = delta;
1390 }
1391 }
1392 }
1393 }
1394 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) )
1395 {
1396 // rounding problem?
1397 for ( int row = 0; row < nrows; ++row )
1398 m_rowHeights[ row ] = sz.y / nrows;
1399 }
1400
1401 // the same logic as above but for the columns
1402 if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) )
1403 {
1404 int sum_proportions = 0;
1405 int growable_space = 0;
1406 int num = 0;
1407 size_t idx;
1408 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1409 {
1410 // Since the number of rows/columns can change as items are
1411 // inserted/deleted, we need to verify at runtime that the
1412 // requested growable rows/columns are still valid.
1413 if (m_growableCols[idx] >= ncols)
1414 continue;
1415
1416 // If all items in a row/column are hidden, that row/column will
1417 // have a dimension of -1. This causes the column to be hidden
1418 // completely.
1419 if (m_colWidths[ m_growableCols[idx] ] == -1)
1420 continue;
1421 sum_proportions += m_growableColsProportions[idx];
1422 growable_space += m_colWidths[ m_growableCols[idx] ];
1423 num++;
1424 }
1425
1426 if (num > 0)
1427 {
1428 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
1429 {
1430 if (m_growableCols[idx] >= ncols )
1431 continue;
1432 if (m_colWidths[ m_growableCols[idx] ] == -1)
1433 m_colWidths[ m_growableCols[idx] ] = 0;
1434 else
1435 {
1436 int delta = (sz.x - minsz.x);
1437 if (sum_proportions == 0)
1438 delta = (delta/num) + m_colWidths[ m_growableCols[idx] ];
1439 else
1440 delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions;
1441 m_colWidths[ m_growableCols[idx] ] = delta;
1442 }
1443 }
1444 }
1445 }
1446 else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) )
1447 {
1448 for ( int col=0; col < ncols; ++col )
1449 m_colWidths[ col ] = sz.x / ncols;
1450 }
1451 }
1452
1453
1454 void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion )
1455 {
1456 m_growableRows.Add( idx );
1457 m_growableRowsProportions.Add( proportion );
1458 }
1459
1460 void wxFlexGridSizer::RemoveGrowableRow( size_t idx )
1461 {
1462 m_growableRows.Remove( idx );
1463 }
1464
1465 void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion )
1466 {
1467 m_growableCols.Add( idx );
1468 m_growableColsProportions.Add( proportion );
1469 }
1470
1471 void wxFlexGridSizer::RemoveGrowableCol( size_t idx )
1472 {
1473 m_growableCols.Remove( idx );
1474 }
1475
1476 //---------------------------------------------------------------------------
1477 // wxBoxSizer
1478 //---------------------------------------------------------------------------
1479
1480 wxBoxSizer::wxBoxSizer( int orient )
1481 : m_orient( orient )
1482 {
1483 }
1484
1485 void wxBoxSizer::RecalcSizes()
1486 {
1487 if (m_children.GetCount() == 0)
1488 return;
1489
1490 int delta = 0;
1491 if (m_stretchable)
1492 {
1493 if (m_orient == wxHORIZONTAL)
1494 delta = m_size.x - m_fixedWidth;
1495 else
1496 delta = m_size.y - m_fixedHeight;
1497 }
1498
1499 wxPoint pt( m_position );
1500
1501 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1502 while (node)
1503 {
1504 wxSizerItem *item = node->GetData();
1505
1506 if (item->IsShown())
1507 {
1508 wxSize size( item->GetMinSizeWithBorder() );
1509
1510 if (m_orient == wxVERTICAL)
1511 {
1512 wxCoord height = size.y;
1513 if (item->GetProportion())
1514 {
1515 // Because of at least one visible item has non-zero
1516 // proportion then m_stretchable is not zero
1517 height = (delta * item->GetProportion()) / m_stretchable;
1518 }
1519
1520 wxPoint child_pos( pt );
1521 wxSize child_size( size.x, height );
1522
1523 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1524 child_size.x = m_size.x;
1525 else if (item->GetFlag() & wxALIGN_RIGHT)
1526 child_pos.x += m_size.x - size.x;
1527 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1528 // XXX wxCENTER is added for backward compatibility;
1529 // wxALIGN_CENTER should be used in new code
1530 child_pos.x += (m_size.x - size.x) / 2;
1531
1532 item->SetDimension( child_pos, child_size );
1533
1534 pt.y += height;
1535 }
1536 else
1537 {
1538 wxCoord width = size.x;
1539 if (item->GetProportion())
1540 {
1541 // Because of at least one visible item has non-zero
1542 // proportion then m_stretchable is not zero
1543 width = (delta * item->GetProportion()) / m_stretchable;
1544 }
1545
1546 wxPoint child_pos( pt );
1547 wxSize child_size( width, size.y );
1548
1549 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1550 child_size.y = m_size.y;
1551 else if (item->GetFlag() & wxALIGN_BOTTOM)
1552 child_pos.y += m_size.y - size.y;
1553 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1554 // XXX wxCENTER is added for backward compatibility;
1555 // wxALIGN_CENTER should be used in new code
1556 child_pos.y += (m_size.y - size.y) / 2;
1557
1558 item->SetDimension( child_pos, child_size );
1559
1560 pt.x += width;
1561 }
1562 }
1563
1564 node = node->GetNext();
1565 }
1566 }
1567
1568 wxSize wxBoxSizer::CalcMin()
1569 {
1570 if (m_children.GetCount() == 0)
1571 return wxSize(10,10);
1572
1573 m_stretchable = 0;
1574 m_minWidth = 0;
1575 m_minHeight = 0;
1576 m_fixedWidth = 0;
1577 m_fixedHeight = 0;
1578
1579 // precalc item minsizes and count proportions
1580 wxSizerItemList::compatibility_iterator node = m_children.GetFirst();
1581 while (node)
1582 {
1583 wxSizerItem *item = node->GetData();
1584
1585 if ( item->IsShown() )
1586 {
1587 item->CalcMin(); // result is stored in the item
1588
1589 m_stretchable += item->GetProportion();
1590 }
1591
1592 node = node->GetNext();
1593 }
1594
1595 // Total minimum size (width or height) of sizer
1596 int maxMinSize = 0;
1597
1598 node = m_children.GetFirst();
1599 while (node)
1600 {
1601 wxSizerItem *item = node->GetData();
1602
1603 if (item->IsShown() && item->GetProportion() != 0)
1604 {
1605 int stretch = item->GetProportion();
1606 wxSize size( item->GetMinSizeWithBorder() );
1607 int minSize;
1608
1609 // Integer division rounded up is (a + b - 1) / b
1610 // Round up needed in order to guarantee that all
1611 // all items will have size not less then their min size
1612 if (m_orient == wxHORIZONTAL)
1613 minSize = ( size.x*m_stretchable + stretch - 1)/stretch;
1614 else
1615 minSize = ( size.y*m_stretchable + stretch - 1)/stretch;
1616
1617 if (minSize > maxMinSize)
1618 maxMinSize = minSize;
1619 }
1620 node = node->GetNext();
1621 }
1622
1623 // Calculate overall minimum size
1624 node = m_children.GetFirst();
1625 while (node)
1626 {
1627 wxSizerItem *item = node->GetData();
1628
1629 if (item->IsShown())
1630 {
1631 wxSize size( item->GetMinSizeWithBorder() );
1632 if (item->GetProportion() != 0)
1633 {
1634 if (m_orient == wxHORIZONTAL)
1635 size.x = (maxMinSize*item->GetProportion())/m_stretchable;
1636 else
1637 size.y = (maxMinSize*item->GetProportion())/m_stretchable;
1638 }
1639 else
1640 {
1641 if (m_orient == wxVERTICAL)
1642 {
1643 m_fixedHeight += size.y;
1644 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1645 }
1646 else
1647 {
1648 m_fixedWidth += size.x;
1649 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1650 }
1651 }
1652
1653 if (m_orient == wxHORIZONTAL)
1654 {
1655 m_minWidth += size.x;
1656 m_minHeight = wxMax( m_minHeight, size.y );
1657 }
1658 else
1659 {
1660 m_minHeight += size.y;
1661 m_minWidth = wxMax( m_minWidth, size.x );
1662 }
1663 }
1664 node = node->GetNext();
1665 }
1666
1667 return wxSize( m_minWidth, m_minHeight );
1668 }
1669
1670 //---------------------------------------------------------------------------
1671 // wxStaticBoxSizer
1672 //---------------------------------------------------------------------------
1673
1674 #if wxUSE_STATBOX
1675
1676 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1677 : wxBoxSizer( orient )
1678 , m_staticBox( box )
1679 {
1680 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1681 }
1682
1683 wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s)
1684 : wxBoxSizer(orient),
1685 m_staticBox(new wxStaticBox(win, wxID_ANY, s))
1686 {
1687 }
1688
1689 static void GetStaticBoxBorders( wxStaticBox *box,
1690 int *borderTop,
1691 int *borderOther)
1692 {
1693 // this has to be done platform by platform as there is no way to
1694 // guess the thickness of a wxStaticBox border
1695 box->GetBordersForSizer(borderTop, borderOther);
1696 }
1697
1698 void wxStaticBoxSizer::RecalcSizes()
1699 {
1700 int top_border, other_border;
1701 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1702
1703 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1704
1705 wxPoint old_pos( m_position );
1706 m_position.x += other_border;
1707 m_position.y += top_border;
1708 wxSize old_size( m_size );
1709 m_size.x -= 2*other_border;
1710 m_size.y -= top_border + other_border;
1711
1712 wxBoxSizer::RecalcSizes();
1713
1714 m_position = old_pos;
1715 m_size = old_size;
1716 }
1717
1718 wxSize wxStaticBoxSizer::CalcMin()
1719 {
1720 int top_border, other_border;
1721 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1722
1723 wxSize ret( wxBoxSizer::CalcMin() );
1724 ret.x += 2*other_border;
1725 ret.y += other_border + top_border;
1726
1727 return ret;
1728 }
1729
1730 void wxStaticBoxSizer::ShowItems( bool show )
1731 {
1732 m_staticBox->Show( show );
1733 wxBoxSizer::ShowItems( show );
1734 }
1735
1736 #endif // wxUSE_STATBOX
1737
1738 #if wxUSE_BUTTON
1739
1740 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1741 : wxBoxSizer(wxHORIZONTAL)
1742 {
1743 // Vertical buttons with lots of space on either side
1744 // looks rubbish on WinCE, so let's not do this for now.
1745 // If we are going to use vertical buttons, we should
1746 // put the sizer to the right of other controls in the dialog,
1747 // and that's beyond the scope of this sizer.
1748 #ifndef __WXWINCE__
1749 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1750 // If we have a PDA screen, put yes/no button over
1751 // all other buttons, otherwise on the left side.
1752 if (is_pda)
1753 m_orient = wxVERTICAL;
1754 #endif
1755
1756 m_buttonAffirmative = NULL;
1757 m_buttonApply = NULL;
1758 m_buttonNegative = NULL;
1759 m_buttonCancel = NULL;
1760 m_buttonHelp = NULL;
1761 }
1762
1763 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1764 {
1765 switch (mybutton->GetId())
1766 {
1767 case wxID_OK:
1768 case wxID_YES:
1769 case wxID_SAVE:
1770 m_buttonAffirmative = mybutton;
1771 break;
1772 case wxID_APPLY:
1773 m_buttonApply = mybutton;
1774 break;
1775 case wxID_NO:
1776 m_buttonNegative = mybutton;
1777 break;
1778 case wxID_CANCEL:
1779 m_buttonCancel = mybutton;
1780 break;
1781 case wxID_HELP:
1782 case wxID_CONTEXT_HELP:
1783 m_buttonHelp = mybutton;
1784 break;
1785 default:
1786 break;
1787 }
1788 }
1789
1790 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1791 {
1792 m_buttonAffirmative = button;
1793 }
1794
1795 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1796 {
1797 m_buttonNegative = button;
1798 }
1799
1800 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1801 {
1802 m_buttonCancel = button;
1803 }
1804
1805 void wxStdDialogButtonSizer::Realize()
1806 {
1807 #ifdef __WXMAC__
1808 Add(0, 0, 0, wxLEFT, 6);
1809 if (m_buttonHelp)
1810 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1811
1812 if (m_buttonNegative){
1813 // HIG POLICE BULLETIN - destructive buttons need extra padding
1814 // 24 pixels on either side
1815 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1816 }
1817
1818 // extra whitespace between help/negative and cancel/ok buttons
1819 Add(0, 0, 1, wxEXPAND, 0);
1820
1821 if (m_buttonCancel){
1822 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1823 // Cancel or help should be default
1824 // m_buttonCancel->SetDefaultButton();
1825 }
1826
1827 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1828 // figure the best place is between Cancel and OK
1829 if (m_buttonApply)
1830 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1831
1832 if (m_buttonAffirmative){
1833 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1834
1835 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1836 // these buttons have set labels under Mac so we should use them
1837 m_buttonAffirmative->SetLabel(_("Save"));
1838 m_buttonNegative->SetLabel(_("Don't Save"));
1839 }
1840 }
1841
1842 // Extra space around and at the right
1843 Add(12, 24);
1844 #elif defined(__WXGTK20__)
1845 Add(0, 0, 0, wxLEFT, 9);
1846 if (m_buttonHelp)
1847 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1848
1849 // extra whitespace between help and cancel/ok buttons
1850 Add(0, 0, 1, wxEXPAND, 0);
1851
1852 if (m_buttonNegative){
1853 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1854 }
1855
1856 if (m_buttonCancel){
1857 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1858 // Cancel or help should be default
1859 // m_buttonCancel->SetDefaultButton();
1860 }
1861
1862 if (m_buttonApply)
1863 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1864
1865 if (m_buttonAffirmative)
1866 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1867 #elif defined(__WXMSW__)
1868 // Windows
1869
1870 // right-justify buttons
1871 Add(0, 0, 1, wxEXPAND, 0);
1872
1873 if (m_buttonAffirmative){
1874 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x);
1875 }
1876
1877 if (m_buttonNegative){
1878 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x);
1879 }
1880
1881 if (m_buttonCancel){
1882 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x);
1883 }
1884 if (m_buttonApply)
1885 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x);
1886
1887 if (m_buttonHelp)
1888 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x);
1889 #else
1890 // GTK+1 and any other platform
1891
1892 // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog
1893 if (m_buttonHelp)
1894 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1895
1896 // extra whitespace between help and cancel/ok buttons
1897 Add(0, 0, 1, wxEXPAND, 0);
1898
1899 if (m_buttonApply)
1900 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1901
1902 if (m_buttonAffirmative){
1903 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1904 }
1905
1906 if (m_buttonNegative){
1907 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1908 }
1909
1910 if (m_buttonCancel){
1911 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
1912 // Cancel or help should be default
1913 // m_buttonCancel->SetDefaultButton();
1914 }
1915
1916 #endif
1917 }
1918
1919 #endif // wxUSE_BUTTON
1920
1921 #if WXWIN_COMPATIBILITY_2_4
1922
1923 // ----------------------------------------------------------------------------
1924 // wxNotebookSizer
1925 // ----------------------------------------------------------------------------
1926
1927 #if wxUSE_BOOKCTRL
1928 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1929 #if wxUSE_NOTEBOOK
1930 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1931 #endif // wxUSE_NOTEBOOK
1932 #endif // wxUSE_BOOKCTRL
1933
1934 #if wxUSE_BOOKCTRL
1935
1936 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
1937 : m_bookctrl(bookctrl)
1938 {
1939 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
1940 }
1941
1942 void wxBookCtrlSizer::RecalcSizes()
1943 {
1944 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1945 }
1946
1947 wxSize wxBookCtrlSizer::CalcMin()
1948 {
1949 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0));
1950
1951 sizeBorder.x += 5;
1952 sizeBorder.y += 5;
1953
1954 if ( m_bookctrl->GetPageCount() == 0 )
1955 {
1956 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1957 }
1958
1959 int maxX = 0;
1960 int maxY = 0;
1961
1962 wxWindowList::compatibility_iterator
1963 node = m_bookctrl->GetChildren().GetFirst();
1964 while (node)
1965 {
1966 wxWindow *item = node->GetData();
1967 wxSizer *itemsizer = item->GetSizer();
1968
1969 if (itemsizer)
1970 {
1971 wxSize subsize( itemsizer->CalcMin() );
1972
1973 if (subsize.x > maxX)
1974 maxX = subsize.x;
1975 if (subsize.y > maxY)
1976 maxY = subsize.y;
1977 }
1978
1979 node = node->GetNext();
1980 }
1981
1982 return wxSize( maxX, maxY ) + sizeBorder;
1983 }
1984
1985 #if wxUSE_NOTEBOOK
1986
1987 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
1988 {
1989 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
1990 m_bookctrl = nb;
1991 }
1992
1993 #endif // wxUSE_NOTEBOOOK
1994 #endif // wxUSE_BOOKCTRL
1995
1996 #endif // WXWIN_COMPATIBILITY_2_4