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