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