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