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