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