]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
Patch [ 1100272 ] wxFlexGridSizer works wrong when some rows/cols are hidden
[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( 0, 0, 0, 0 )
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( 0, 0, 0, 0 )
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( 0, 0, 0, 0 )
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( wxSize( 0, 0 ) )
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 static void GetStaticBoxBorders( wxStaticBox *box,
1574 int *borderTop,
1575 int *borderOther)
1576 {
1577 // this has to be done platform by platform as there is no way to
1578 // guess the thickness of a wxStaticBox border
1579 #ifdef __WXCOCOA__
1580 box->GetBordersForSizer(borderTop,borderOther);
1581 #elif defined(__WXMAC__)
1582
1583 static int extraTop = -1; // Uninitted
1584 static int other = 5;
1585
1586 if ( extraTop == -1 )
1587 {
1588 // The minimal border used for the top. Later on the staticbox'
1589 // font height is added to this.
1590 extraTop = 0;
1591
1592 if ( UMAGetSystemVersion() >= 0x1030 /*Panther*/ )
1593 {
1594 // As indicated by the HIG, Panther needs an extra border of 11
1595 // pixels (otherwise overlapping occurs at the top). The "other"
1596 // border has to be 11.
1597 extraTop = 11;
1598 other = 11;
1599 }
1600
1601 }
1602
1603 *borderTop = extraTop + box->GetCharHeight();
1604 *borderOther = other;
1605
1606 #else
1607 #ifdef __WXGTK__
1608 if ( box->GetLabel().empty() )
1609 *borderTop = 5;
1610 else
1611 #endif // __WXGTK__
1612 *borderTop = box->GetCharHeight();
1613
1614 *borderOther = 5;
1615 #endif // __WXCOCOA__
1616 }
1617
1618 void wxStaticBoxSizer::RecalcSizes()
1619 {
1620 int top_border, other_border;
1621 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1622
1623 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1624
1625 wxPoint old_pos( m_position );
1626 m_position.x += other_border;
1627 m_position.y += top_border;
1628 wxSize old_size( m_size );
1629 m_size.x -= 2*other_border;
1630 m_size.y -= top_border + other_border;
1631
1632 wxBoxSizer::RecalcSizes();
1633
1634 m_position = old_pos;
1635 m_size = old_size;
1636 }
1637
1638 wxSize wxStaticBoxSizer::CalcMin()
1639 {
1640 int top_border, other_border;
1641 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1642
1643 wxSize ret( wxBoxSizer::CalcMin() );
1644 ret.x += 2*other_border;
1645 ret.y += other_border + top_border;
1646
1647 return ret;
1648 }
1649
1650 void wxStaticBoxSizer::ShowItems( bool show )
1651 {
1652 m_staticBox->Show( show );
1653 wxBoxSizer::ShowItems( show );
1654 }
1655
1656 #endif // wxUSE_STATBOX
1657
1658 #if wxUSE_BUTTON
1659
1660 wxStdDialogButtonSizer::wxStdDialogButtonSizer()
1661 : wxBoxSizer(wxHORIZONTAL)
1662 {
1663 bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA);
1664
1665 // If we have a PDA screen, put yes/no button over
1666 // all other buttons, otherwise on the left side.
1667 if (is_pda)
1668 m_orient = wxVERTICAL;
1669
1670 m_buttonAffirmative = NULL;
1671 m_buttonApply = NULL;
1672 m_buttonNegative = NULL;
1673 m_buttonCancel = NULL;
1674 m_buttonHelp = NULL;
1675 }
1676
1677 void wxStdDialogButtonSizer::AddButton(wxButton *mybutton)
1678 {
1679 switch (mybutton->GetId())
1680 {
1681 case wxID_OK:
1682 case wxID_YES:
1683 case wxID_SAVE:
1684 m_buttonAffirmative = mybutton;
1685 break;
1686 case wxID_APPLY:
1687 m_buttonApply = mybutton;
1688 break;
1689 case wxID_NO:
1690 m_buttonNegative = mybutton;
1691 break;
1692 case wxID_CANCEL:
1693 m_buttonCancel = mybutton;
1694 break;
1695 case wxID_HELP:
1696 m_buttonHelp = mybutton;
1697 break;
1698 default:
1699 break;
1700 }
1701 }
1702
1703 void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button )
1704 {
1705 m_buttonAffirmative = button;
1706 }
1707
1708 void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button )
1709 {
1710 m_buttonNegative = button;
1711 }
1712
1713 void wxStdDialogButtonSizer::SetCancelButton( wxButton *button )
1714 {
1715 m_buttonCancel = button;
1716 }
1717
1718 void wxStdDialogButtonSizer::Finalise()
1719 {
1720 #ifdef __WXMAC__
1721 Add(0, 0, 0, wxLEFT, 6);
1722 if (m_buttonHelp)
1723 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1724
1725 if (m_buttonNegative){
1726 // HIG POLICE BULLETIN - destructive buttons need extra padding
1727 // 24 pixels on either side
1728 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12);
1729 }
1730
1731 // extra whitespace between help/negative and cancel/ok buttons
1732 Add(0, 0, 1, wxEXPAND, 0);
1733
1734 if (m_buttonCancel){
1735 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1736 // Cancel or help should be default
1737 // m_buttonCancel->SetDefaultButton();
1738 }
1739
1740 // Ugh, Mac doesn't really have apply dialogs, so I'll just
1741 // figure the best place is between Cancel and OK
1742 if (m_buttonApply)
1743 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6);
1744
1745 if (m_buttonAffirmative){
1746 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1747
1748 if (m_buttonAffirmative->GetId() == wxID_SAVE){
1749 // these buttons have set labels under Mac so we should use them
1750 m_buttonAffirmative->SetLabel(_("Save"));
1751 m_buttonNegative->SetLabel(_("Don't Save"));
1752 }
1753 }
1754
1755 // Extra space around and at the right
1756 Add(12, 24);
1757 #elif defined(__WXGTK20__)
1758 Add(0, 0, 0, wxLEFT, 9);
1759 if (m_buttonHelp)
1760 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1761
1762 // extra whitespace between help and cancel/ok buttons
1763 Add(0, 0, 1, wxEXPAND, 0);
1764
1765 if (m_buttonNegative){
1766 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1767 }
1768
1769 if (m_buttonCancel){
1770 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1771 // Cancel or help should be default
1772 // m_buttonCancel->SetDefaultButton();
1773 }
1774
1775 if (m_buttonApply)
1776 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3);
1777
1778 if (m_buttonAffirmative)
1779 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6);
1780 #else
1781 // do the same thing for GTK1 and Windows platforms
1782 // and assume any platform not accounted for here will use
1783 // Windows style
1784 Add(0, 0, 0, wxLEFT, 9);
1785 if (m_buttonHelp)
1786 Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x);
1787
1788 // extra whitespace between help and cancel/ok buttons
1789 Add(0, 0, 1, wxEXPAND, 0);
1790
1791 if (m_buttonApply)
1792 Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x);
1793
1794 if (m_buttonAffirmative){
1795 Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x);
1796 }
1797
1798 if (m_buttonNegative){
1799 Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x);
1800 }
1801
1802 if (m_buttonCancel){
1803 Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x);
1804 // Cancel or help should be default
1805 // m_buttonCancel->SetDefaultButton();
1806 }
1807
1808 #endif
1809 }
1810
1811 #endif // wxUSE_BUTTON
1812
1813 #if WXWIN_COMPATIBILITY_2_4
1814
1815 // ----------------------------------------------------------------------------
1816 // wxNotebookSizer
1817 // ----------------------------------------------------------------------------
1818
1819 #if wxUSE_BOOKCTRL
1820 IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer)
1821 #if wxUSE_NOTEBOOK
1822 IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer)
1823 #endif // wxUSE_NOTEBOOK
1824 #endif // wxUSE_BOOKCTRL
1825
1826 #if wxUSE_BOOKCTRL
1827
1828 wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl)
1829 : m_bookctrl(bookctrl)
1830 {
1831 wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") );
1832 }
1833
1834 void wxBookCtrlSizer::RecalcSizes()
1835 {
1836 m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1837 }
1838
1839 wxSize wxBookCtrlSizer::CalcMin()
1840 {
1841 wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0, 0));
1842
1843 sizeBorder.x += 5;
1844 sizeBorder.y += 5;
1845
1846 if ( m_bookctrl->GetPageCount() == 0 )
1847 {
1848 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1849 }
1850
1851 int maxX = 0;
1852 int maxY = 0;
1853
1854 wxWindowList::compatibility_iterator
1855 node = m_bookctrl->GetChildren().GetFirst();
1856 while (node)
1857 {
1858 wxWindow *item = node->GetData();
1859 wxSizer *itemsizer = item->GetSizer();
1860
1861 if (itemsizer)
1862 {
1863 wxSize subsize( itemsizer->CalcMin() );
1864
1865 if (subsize.x > maxX)
1866 maxX = subsize.x;
1867 if (subsize.y > maxY)
1868 maxY = subsize.y;
1869 }
1870
1871 node = node->GetNext();
1872 }
1873
1874 return wxSize( maxX, maxY ) + sizeBorder;
1875 }
1876
1877 #if wxUSE_NOTEBOOK
1878
1879 wxNotebookSizer::wxNotebookSizer(wxNotebook *nb)
1880 {
1881 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") );
1882 m_bookctrl = nb;
1883 }
1884
1885 #endif // wxUSE_NOTEBOOOK
1886 #endif // wxUSE_BOOKCTRL
1887
1888 #endif // WXWIN_COMPATIBILITY_2_4