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