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