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