]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/sizer.cpp
Added compatibility file
[wxWidgets.git] / src / common / sizer.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: sizer.cpp
3// Purpose: provide new wxSizer class for layout
4// Author: Robert Roebling and Robin Dunn
5// Modified by:
6// Created:
7// RCS-ID: $Id$
8// Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12#ifdef __GNUG__
13#pragma implementation "sizer.h"
14#endif
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
23#include "wx/sizer.h"
24#include "wx/utils.h"
25#include "wx/statbox.h"
26#include "wx/notebook.h"
27
28//---------------------------------------------------------------------------
29
30IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject)
31IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject)
32IMPLEMENT_ABSTRACT_CLASS(wxGridSizer, wxSizer)
33IMPLEMENT_ABSTRACT_CLASS(wxFlexGridSizer, wxGridSizer)
34IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer)
35#if wxUSE_STATBOX
36IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer)
37#endif
38#if wxUSE_NOTEBOOK
39IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer)
40#endif
41
42//---------------------------------------------------------------------------
43// wxSizerItem
44//---------------------------------------------------------------------------
45
46wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
47{
48 m_window = (wxWindow *) NULL;
49 m_sizer = (wxSizer *) NULL;
50 m_option = option;
51 m_border = border;
52 m_flag = flag;
53 m_userData = userData;
54
55 // minimal size is the initial size
56 m_minSize.x = width;
57 m_minSize.y = height;
58
59 SetRatio(width, height);
60
61 // size is set directly
62 m_size = m_minSize;
63}
64
65wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
66{
67 m_window = window;
68 m_sizer = (wxSizer *) NULL;
69 m_option = option;
70 m_border = border;
71 m_flag = flag;
72 m_userData = userData;
73
74 // minimal size is the initial size
75 m_minSize = window->GetSize();
76
77 // aspect ratio calculated from initial size
78 SetRatio(m_minSize);
79
80 // size is calculated later
81 // m_size = ...
82}
83
84wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
85{
86 m_window = (wxWindow *) NULL;
87 m_sizer = sizer;
88 m_option = option;
89 m_border = border;
90 m_flag = flag;
91 m_userData = userData;
92
93 // minimal size is calculated later
94 // m_minSize = ...
95 m_ratio = 0;
96
97 // size is calculated later
98 // m_size = ...
99}
100
101wxSizerItem::~wxSizerItem()
102{
103 if (m_userData)
104 delete m_userData;
105 if (m_sizer)
106 delete m_sizer;
107}
108
109
110wxSize wxSizerItem::GetSize()
111{
112 wxSize ret;
113 if (IsSizer())
114 ret = m_sizer->GetSize();
115 else
116 if (IsWindow())
117 ret = m_window->GetSize();
118 else ret = m_size;
119
120 if (m_flag & wxWEST)
121 ret.x += m_border;
122 if (m_flag & wxEAST)
123 ret.x += m_border;
124 if (m_flag & wxNORTH)
125 ret.y += m_border;
126 if (m_flag & wxSOUTH)
127 ret.y += m_border;
128
129 return ret;
130}
131
132wxSize wxSizerItem::CalcMin()
133{
134 wxSize ret;
135 if (IsSizer())
136 {
137 ret = m_sizer->GetMinSize();
138
139 // if we have to preserve aspect ratio _AND_ this is
140 // the first-time calculation, consider ret to be initial size
141 if ((m_flag & wxSHAPED) && !m_ratio)
142 SetRatio(ret);
143 }
144 else
145 {
146 if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
147 {
148 // check if the best (minimal, in fact) window size hadn't changed
149 // by chance: this may happen for, e.g. static text if its label
150 // changed
151 wxSize size = m_window->GetBestSize();
152 if ( size.x > m_minSize.x )
153 m_minSize.x = size.x;
154 if ( size.y > m_minSize.y )
155 m_minSize.y = size.y;
156 }
157
158 ret = m_minSize;
159 }
160
161 if (m_flag & wxWEST)
162 ret.x += m_border;
163 if (m_flag & wxEAST)
164 ret.x += m_border;
165 if (m_flag & wxNORTH)
166 ret.y += m_border;
167 if (m_flag & wxSOUTH)
168 ret.y += m_border;
169
170 return ret;
171}
172
173void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
174{
175 if (m_flag & wxSHAPED)
176 {
177 // adjust aspect ratio
178 int rwidth = (int) (size.y * m_ratio);
179 if (rwidth > size.x)
180 {
181 // fit horizontally
182 int rheight = (int) (size.x / m_ratio);
183 // add vertical space
184 if (m_flag & wxALIGN_CENTER_VERTICAL)
185 pos.y += (size.y - rheight) / 2;
186 else if (m_flag & wxALIGN_BOTTOM)
187 pos.y += (size.y - rheight);
188 // use reduced dimensions
189 size.y =rheight;
190 }
191 else if (rwidth < size.x)
192 {
193 // add horizontal space
194 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
195 pos.x += (size.x - rwidth) / 2;
196 else if (m_flag & wxALIGN_RIGHT)
197 pos.x += (size.x - rwidth);
198 size.x = rwidth;
199 }
200 }
201
202 // This is what GetPosition() returns. Since we calculate
203 // borders afterwards, GetPosition() will be the left/top
204 // corner of the surrounding border.
205 m_pos = pos;
206
207 if (m_flag & wxWEST)
208 {
209 pos.x += m_border;
210 size.x -= m_border;
211 }
212 if (m_flag & wxEAST)
213 {
214 size.x -= m_border;
215 }
216 if (m_flag & wxNORTH)
217 {
218 pos.y += m_border;
219 size.y -= m_border;
220 }
221 if (m_flag & wxSOUTH)
222 {
223 size.y -= m_border;
224 }
225
226 if (IsSizer())
227 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
228
229 if (IsWindow())
230 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
231
232 m_size = size;
233}
234
235void wxSizerItem::DeleteWindows()
236{
237 if (m_window)
238 m_window->Destroy();
239
240 if (m_sizer)
241 m_sizer->DeleteWindows();
242}
243
244bool wxSizerItem::IsWindow()
245{
246 return (m_window != NULL);
247}
248
249bool wxSizerItem::IsSizer()
250{
251 return (m_sizer != NULL);
252}
253
254bool wxSizerItem::IsSpacer()
255{
256 return (m_window == NULL) && (m_sizer == NULL);
257}
258
259//---------------------------------------------------------------------------
260// wxSizer
261//---------------------------------------------------------------------------
262
263wxSizer::wxSizer()
264{
265 m_children.DeleteContents( TRUE );
266 m_minSize.x = 0;
267 m_minSize.y = 0;
268}
269
270wxSizer::~wxSizer()
271{
272 Clear();
273}
274
275void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
276{
277 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
278 window->SetContainingSizer(this);
279}
280
281void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
282{
283 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
284}
285
286void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
287{
288 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
289}
290
291void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
292{
293 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
294 window->SetContainingSizer(this);
295}
296
297void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
298{
299 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
300}
301
302void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
303{
304 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
305}
306
307void wxSizer::Insert( int before, wxWindow *window, int option, int flag, int border, wxObject* userData )
308{
309 m_children.Insert( before, new wxSizerItem( window, option, flag, border, userData ) );
310 window->SetContainingSizer(this);
311}
312
313void wxSizer::Insert( int before, wxSizer *sizer, int option, int flag, int border, wxObject* userData )
314{
315 m_children.Insert( before, new wxSizerItem( sizer, option, flag, border, userData ) );
316}
317
318void wxSizer::Insert( int before, int width, int height, int option, int flag, int border, wxObject* userData )
319{
320 m_children.Insert( before, new wxSizerItem( width, height, option, flag, border, userData ) );
321}
322
323bool wxSizer::Remove( wxWindow *window )
324{
325 wxASSERT( window );
326
327 wxNode *node = m_children.First();
328 while (node)
329 {
330 wxSizerItem *item = (wxSizerItem*)node->Data();
331 if (item->GetWindow() == window)
332 {
333 item->GetWindow()->SetContainingSizer(NULL);
334 m_children.DeleteNode( node );
335 return TRUE;
336 }
337 node = node->Next();
338 }
339
340 return FALSE;
341}
342
343bool wxSizer::Remove( wxSizer *sizer )
344{
345 wxASSERT( sizer );
346
347 wxNode *node = m_children.First();
348 while (node)
349 {
350 wxSizerItem *item = (wxSizerItem*)node->Data();
351 if (item->GetSizer() == sizer)
352 {
353 m_children.DeleteNode( node );
354 return TRUE;
355 }
356 node = node->Next();
357 }
358
359 return FALSE;
360}
361
362bool wxSizer::Remove( int pos )
363{
364 wxNode *node = m_children.Nth( pos );
365 if (!node) return FALSE;
366
367 m_children.DeleteNode( node );
368
369 return TRUE;
370}
371
372void wxSizer::Clear( bool delete_windows )
373{
374 // First clear the ContainingSizer pointers
375 wxNode *node = m_children.First();
376 while (node)
377 {
378 wxSizerItem *item = (wxSizerItem*)node->Data();
379 if (item->IsWindow())
380 item->GetWindow()->SetContainingSizer(NULL);
381 node = node->Next();
382 }
383
384 // Destroy the windows if needed
385 if (delete_windows)
386 DeleteWindows();
387
388 // Now empty the list
389 m_children.Clear();
390}
391
392void wxSizer::DeleteWindows()
393{
394 wxNode *node = m_children.First();
395 while (node)
396 {
397 wxSizerItem *item = (wxSizerItem*)node->Data();
398 item->DeleteWindows();
399 node = node->Next();
400 }
401}
402
403void wxSizer::Fit( wxWindow *window )
404{
405 wxSize size;
406 if (window->IsTopLevel())
407 size = FitSize( window );
408 else
409 size = GetMinWindowSize( window );
410
411 window->SetSize( size );
412}
413
414void wxSizer::Layout()
415{
416 CalcMin();
417 RecalcSizes();
418}
419
420void wxSizer::SetSizeHints( wxWindow *window )
421{
422 wxSize size = FitSize( window );
423 window->SetSizeHints( size.x, size.y );
424}
425
426wxSize wxSizer::GetMaxWindowSize( wxWindow *WXUNUSED(window) )
427{
428 wxRect rect = wxGetClientDisplayRect();
429 wxSize sizeMax (rect.width,rect.height);
430
431 // Sorry, but this bit is wrong -- it makes a window that should just be
432 // able to fit onto the screen, not fit on the screen. -- JACS
433#if 0
434 // Make the max size a bit smaller than the visible portion of
435 // the screen. A window which takes the entire screen doesn't
436 // look very nice either
437 sizeMax.x *= 9;
438 sizeMax.x /= 10;
439
440 sizeMax.y *= 9;
441 sizeMax.y /= 10;
442#endif
443
444 return sizeMax;
445}
446
447wxSize wxSizer::GetMinWindowSize( wxWindow *window )
448{
449 wxSize minSize( GetMinSize() );
450 wxSize size( window->GetSize() );
451 wxSize client_size( window->GetClientSize() );
452 return wxSize( minSize.x+size.x-client_size.x,
453 minSize.y+size.y-client_size.y );
454}
455
456// Return a window size that will fit within the screens dimensions
457wxSize wxSizer::FitSize( wxWindow *window )
458{
459 wxSize size = GetMinWindowSize( window );
460 wxSize sizeMax = GetMaxWindowSize( window );
461
462 if ( size.x > sizeMax.x )
463 size.x = sizeMax.x;
464 if ( size.y > sizeMax.y )
465 size.y = sizeMax.y;
466
467 return size;
468}
469
470void wxSizer::SetDimension( int x, int y, int width, int height )
471{
472 m_position.x = x;
473 m_position.y = y;
474 m_size.x = width;
475 m_size.y = height;
476 CalcMin();
477 RecalcSizes();
478}
479
480wxSize wxSizer::GetMinSize()
481{
482 wxSize ret( CalcMin() );
483 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
484 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
485 return ret;
486}
487
488void wxSizer::DoSetMinSize( int width, int height )
489{
490 m_minSize.x = width;
491 m_minSize.y = height;
492}
493
494bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
495{
496 wxASSERT( window );
497
498 wxNode *node = m_children.First();
499 while (node)
500 {
501 wxSizerItem *item = (wxSizerItem*)node->Data();
502 if (item->GetWindow() == window)
503 {
504 item->SetInitSize( width, height );
505 return TRUE;
506 }
507 node = node->Next();
508 }
509
510 node = m_children.First();
511 while (node)
512 {
513 wxSizerItem *item = (wxSizerItem*)node->Data();
514 if (item->GetSizer())
515 {
516 /* It's a sizer, so lets search recursively. */
517 if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
518 {
519 /* A child sizer found the requested windw, exit. */
520 return TRUE;
521 }
522 }
523 node = node->Next();
524 }
525
526 return FALSE;
527}
528
529bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
530{
531 wxASSERT( sizer );
532
533 wxNode *node = m_children.First();
534 while (node)
535 {
536 wxSizerItem *item = (wxSizerItem*)node->Data();
537 if (item->GetSizer() == sizer)
538 {
539 item->GetSizer()->DoSetMinSize( width, height );
540 return TRUE;
541 }
542 node = node->Next();
543 }
544
545 node = m_children.First();
546 while (node)
547 {
548 wxSizerItem *item = (wxSizerItem*)node->Data();
549 if (item->GetSizer())
550 {
551 /* It's a sizer, so lets search recursively. */
552 if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
553 {
554 /* A child sizer found the requested windw, exit. */
555 return TRUE;
556 }
557 }
558 node = node->Next();
559 }
560
561 return FALSE;
562}
563
564bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
565{
566 wxNode *node = m_children.Nth( pos );
567 if (!node) return FALSE;
568
569 wxSizerItem *item = (wxSizerItem*) node->Data();
570 if (item->GetSizer())
571 {
572 /* Sizers contains the minimal size in them, if not calculated ... */
573 item->GetSizer()->DoSetMinSize( width, height );
574 }
575 else
576 {
577 /* ... whereas the minimal size of spacers and windows in stored
578 in the item */
579 item->SetInitSize( width, height );
580 }
581
582 return TRUE;
583}
584
585//---------------------------------------------------------------------------
586// wxGridSizer
587//---------------------------------------------------------------------------
588
589wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
590{
591 m_rows = rows;
592 m_cols = cols;
593 m_vgap = vgap;
594 m_hgap = hgap;
595}
596
597wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
598{
599 m_rows = 0;
600 m_cols = cols;
601 m_vgap = vgap;
602 m_hgap = hgap;
603}
604
605void wxGridSizer::RecalcSizes()
606{
607 if (m_children.GetCount() == 0)
608 return;
609
610 int nitems = m_children.GetCount();
611 int nrows = m_rows;
612 int ncols = m_cols;
613
614 if (ncols > 0)
615 nrows = (nitems + ncols-1) / ncols;
616 else
617 ncols = (nitems + nrows-1) / nrows;
618
619 wxSize sz( GetSize() );
620 wxPoint pt( GetPosition() );
621
622 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
623 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
624
625 int x = pt.x;
626 for (int c = 0; c < ncols; c++)
627 {
628 int y = pt.y;
629 for (int r = 0; r < nrows; r++)
630 {
631 int i = r * ncols + c;
632 if (i < nitems)
633 {
634 wxNode *node = m_children.Nth( i );
635 wxASSERT( node );
636
637 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
638 }
639 y = y + h + m_vgap;
640 }
641 x = x + w + m_hgap;
642 }
643}
644
645wxSize wxGridSizer::CalcMin()
646{
647 if (m_children.GetCount() == 0)
648 return wxSize(10,10);
649
650 int nitems = m_children.GetCount();
651 int nrows = m_rows;
652 int ncols = m_cols;
653
654 if (ncols > 0)
655 nrows = (nitems + ncols-1) / ncols;
656 else
657 ncols = (nitems + nrows-1) / nrows;
658
659 /* Find the max width and height for any component */
660 int w = 0;
661 int h = 0;
662
663 wxNode *node = m_children.First();
664 while (node)
665 {
666 wxSizerItem *item = (wxSizerItem*)node->Data();
667 wxSize sz( item->CalcMin() );
668 w = wxMax( w, sz.x );
669 h = wxMax( h, sz.y );
670
671 node = node->Next();
672 }
673
674 return wxSize(ncols * w + (ncols-1) * m_hgap,
675 nrows * h + (nrows-1) * m_vgap);
676}
677
678void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
679{
680 wxPoint pt( x,y );
681 wxSize sz( item->CalcMin() );
682 int flag = item->GetFlag();
683
684 if ((flag & wxEXPAND) || (flag & wxSHAPED))
685 {
686 sz = wxSize(w, h);
687 }
688 else
689 {
690 if (flag & wxALIGN_CENTER_HORIZONTAL)
691 {
692 pt.x = x + (w - sz.x) / 2;
693 }
694 else if (flag & wxALIGN_RIGHT)
695 {
696 pt.x = x + (w - sz.x);
697 }
698
699 if (flag & wxALIGN_CENTER_VERTICAL)
700 {
701 pt.y = y + (h - sz.y) / 2;
702 }
703 else if (flag & wxALIGN_BOTTOM)
704 {
705 pt.y = y + (h - sz.y);
706 }
707 }
708
709 item->SetDimension(pt, sz);
710}
711
712//---------------------------------------------------------------------------
713// wxFlexGridSizer
714//---------------------------------------------------------------------------
715
716wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
717 : wxGridSizer( rows, cols, vgap, hgap )
718{
719 m_rowHeights = (int*) NULL;
720 m_colWidths = (int*) NULL;
721}
722
723wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
724 : wxGridSizer( cols, vgap, hgap )
725{
726 m_rowHeights = (int*) NULL;
727 m_colWidths = (int*) NULL;
728}
729
730wxFlexGridSizer::~wxFlexGridSizer()
731{
732 if (m_rowHeights)
733 delete[] m_rowHeights;
734 if (m_colWidths)
735 delete[] m_colWidths;
736}
737
738void wxFlexGridSizer::CreateArrays()
739{
740 if (m_rowHeights)
741 delete[] m_rowHeights;
742 if (m_colWidths)
743 delete[] m_colWidths;
744
745 if (m_children.GetCount() == 0)
746 return;
747
748 int nitems = m_children.GetCount();
749 int nrows = m_rows;
750 int ncols = m_cols;
751
752 if (ncols > 0)
753 nrows = (nitems + ncols-1) / ncols;
754 else
755 ncols = (nitems + nrows-1) / nrows;
756
757 m_rowHeights = new int[nrows];
758 m_colWidths = new int[ncols];
759
760 for (int col = 0; col < ncols; col++)
761 m_colWidths[ col ] = 0;
762 for (int row = 0; row < nrows; row++)
763 m_rowHeights[ row ] = 0;
764}
765
766void wxFlexGridSizer::RecalcSizes()
767{
768 if (m_children.GetCount() == 0)
769 return;
770
771 int nitems = m_children.GetCount();
772 int nrows = m_rows;
773 int ncols = m_cols;
774
775 if (ncols > 0)
776 nrows = (nitems + ncols-1) / ncols;
777 else
778 ncols = (nitems + nrows-1) / nrows;
779
780 wxSize sz( GetSize() );
781 wxSize minsz( CalcMin() );
782 wxPoint pt( GetPosition() );
783 int delta;
784 size_t idx;
785
786 if ((m_growableRows.GetCount() > 0) && (sz.y > minsz.y))
787 {
788 delta = (sz.y - minsz.y) / m_growableRows.GetCount();
789 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
790 m_rowHeights[ m_growableRows[idx] ] += delta;
791 }
792
793 if ((m_growableCols.GetCount() > 0) && (sz.x > minsz.x))
794 {
795 delta = (sz.x - minsz.x) / m_growableCols.GetCount();
796 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
797 m_colWidths[ m_growableCols[idx] ] += delta;
798 }
799
800 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
801
802 int x = pt.x;
803 for (int c = 0; c < ncols; c++)
804 {
805 int y = pt.y;
806 for (int r = 0; r < nrows; r++)
807 {
808 int i = r * ncols + c;
809 if (i < nitems)
810 {
811 wxNode *node = m_children.Nth( i );
812 wxASSERT( node );
813
814 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
815 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
816
817 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
818 }
819 y = y + m_rowHeights[r] + m_vgap;
820 }
821 x = x + m_colWidths[c] + m_hgap;
822 }
823}
824
825wxSize wxFlexGridSizer::CalcMin()
826{
827 if (m_children.GetCount() == 0)
828 return wxSize(10,10);
829
830 int nitems = m_children.GetCount();
831 int nrows = m_rows;
832 int ncols = m_cols;
833
834 if (ncols > 0)
835 nrows = (nitems + ncols-1) / ncols;
836 else
837 ncols = (nitems + nrows-1) / nrows;
838
839 CreateArrays();
840
841 int col;
842 int row;
843
844 int i = 0;
845 wxNode *node = m_children.First();
846 while (node)
847 {
848 wxSizerItem *item = (wxSizerItem*)node->Data();
849 wxSize sz( item->CalcMin() );
850 row = i / ncols;
851 col = i % ncols;
852 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
853 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
854
855 node = node->Next();
856 i++;
857 }
858
859 int width = 0;
860 for (col = 0; col < ncols; col++)
861 width += m_colWidths[ col ];
862
863 int height = 0;
864 for (row = 0; row < nrows; row++)
865 height += m_rowHeights[ row ];
866
867 return wxSize( width + (ncols-1) * m_hgap,
868 height + (nrows-1) * m_vgap);
869}
870
871void wxFlexGridSizer::AddGrowableRow( size_t idx )
872{
873 m_growableRows.Add( idx );
874}
875
876void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
877{
878}
879
880void wxFlexGridSizer::AddGrowableCol( size_t idx )
881{
882 m_growableCols.Add( idx );
883}
884
885void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
886{
887}
888
889//---------------------------------------------------------------------------
890// wxBoxSizer
891//---------------------------------------------------------------------------
892
893wxBoxSizer::wxBoxSizer( int orient )
894{
895 m_orient = orient;
896}
897
898void wxBoxSizer::RecalcSizes()
899{
900 if (m_children.GetCount() == 0)
901 return;
902
903 int delta = 0;
904 int extra = 0;
905 if (m_stretchable)
906 {
907 if (m_orient == wxHORIZONTAL)
908 {
909 delta = (m_size.x - m_fixedWidth) / m_stretchable;
910 extra = (m_size.x - m_fixedWidth) % m_stretchable;
911 }
912 else
913 {
914 delta = (m_size.y - m_fixedHeight) / m_stretchable;
915 extra = (m_size.y - m_fixedHeight) % m_stretchable;
916 }
917 }
918
919 wxPoint pt( m_position );
920
921 wxNode *node = m_children.GetFirst();
922 while (node)
923 {
924 wxSizerItem *item = (wxSizerItem*) node->Data();
925
926 int weight = 1;
927 if (item->GetOption())
928 weight = item->GetOption();
929
930 wxSize size( item->CalcMin() );
931
932 if (m_orient == wxVERTICAL)
933 {
934 wxCoord height = size.y;
935 if (item->GetOption())
936 {
937 height = (delta * weight) + extra;
938 extra = 0; // only the first item will get the remainder as extra size
939 }
940
941 wxPoint child_pos( pt );
942 wxSize child_size( wxSize( size.x, height) );
943
944 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
945 child_size.x = m_size.x;
946 else if (item->GetFlag() & wxALIGN_RIGHT)
947 child_pos.x += m_size.x - size.x;
948 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
949 // XXX wxCENTER is added for backward compatibility;
950 // wxALIGN_CENTER should be used in new code
951 child_pos.x += (m_size.x - size.x) / 2;
952
953 item->SetDimension( child_pos, child_size );
954
955 pt.y += height;
956 }
957 else
958 {
959 wxCoord width = size.x;
960 if (item->GetOption())
961 {
962 width = (delta * weight) + extra;
963 extra = 0; // only the first item will get the remainder as extra size
964 }
965
966 wxPoint child_pos( pt );
967 wxSize child_size( wxSize(width, size.y) );
968
969 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
970 child_size.y = m_size.y;
971 else if (item->GetFlag() & wxALIGN_BOTTOM)
972 child_pos.y += m_size.y - size.y;
973 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
974 // XXX wxCENTER is added for backward compatibility;
975 // wxALIGN_CENTER should be used in new code
976 child_pos.y += (m_size.y - size.y) / 2;
977
978 item->SetDimension( child_pos, child_size );
979
980 pt.x += width;
981 }
982
983 node = node->Next();
984 }
985}
986
987wxSize wxBoxSizer::CalcMin()
988{
989 if (m_children.GetCount() == 0)
990 return wxSize(10,10);
991
992 m_stretchable = 0;
993 m_minWidth = 0;
994 m_minHeight = 0;
995 m_fixedWidth = 0;
996 m_fixedHeight = 0;
997
998 // Find how long each stretch unit needs to be
999 int stretchSize = 1;
1000 wxNode *node = m_children.GetFirst();
1001 while (node)
1002 {
1003 wxSizerItem *item = (wxSizerItem*) node->Data();
1004 if (item->GetOption() != 0)
1005 {
1006 int stretch = item->GetOption();
1007 wxSize size( item->CalcMin() );
1008 int sizePerStretch;
1009 // Integer division rounded up is (a + b - 1) / b
1010 if (m_orient == wxHORIZONTAL)
1011 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1012 else
1013 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1014 if (sizePerStretch > stretchSize)
1015 stretchSize = sizePerStretch;
1016 }
1017 node = node->Next();
1018 }
1019 // Calculate overall minimum size
1020 node = m_children.GetFirst();
1021 while (node)
1022 {
1023 wxSizerItem *item = (wxSizerItem*) node->Data();
1024
1025 m_stretchable += item->GetOption();
1026
1027 wxSize size( item->CalcMin() );
1028 if (item->GetOption() != 0)
1029 {
1030 if (m_orient == wxHORIZONTAL)
1031 size.x = stretchSize * item->GetOption();
1032 else
1033 size.y = stretchSize * item->GetOption();
1034 }
1035
1036 if (m_orient == wxHORIZONTAL)
1037 {
1038 m_minWidth += size.x;
1039 m_minHeight = wxMax( m_minHeight, size.y );
1040 }
1041 else
1042 {
1043 m_minHeight += size.y;
1044 m_minWidth = wxMax( m_minWidth, size.x );
1045 }
1046
1047 if (item->GetOption() == 0)
1048 {
1049 if (m_orient == wxVERTICAL)
1050 {
1051 m_fixedHeight += size.y;
1052 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1053 }
1054 else
1055 {
1056 m_fixedWidth += size.x;
1057 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1058 }
1059 }
1060
1061 node = node->Next();
1062 }
1063
1064 return wxSize( m_minWidth, m_minHeight );
1065}
1066
1067//---------------------------------------------------------------------------
1068// wxStaticBoxSizer
1069//---------------------------------------------------------------------------
1070
1071#if wxUSE_STATBOX
1072
1073wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1074 : wxBoxSizer( orient )
1075{
1076 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1077
1078 m_staticBox = box;
1079}
1080
1081static void GetStaticBoxBorders(wxStaticBox *box,
1082 int *borderTop, int *borderOther)
1083{
1084 // this has to be done platform by platform as there is no way to
1085 // guess the thickness of a wxStaticBox border
1086#ifdef __WXGTK__
1087 if ( box->GetLabel().IsEmpty() )
1088 *borderTop = 5;
1089 else
1090#endif // __WXGTK__
1091 *borderTop = 15;
1092 (void)box;
1093 *borderOther = 5;
1094}
1095
1096void wxStaticBoxSizer::RecalcSizes()
1097{
1098 int top_border, other_border;
1099 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1100
1101 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1102
1103 wxPoint old_pos( m_position );
1104 m_position.x += other_border;
1105 m_position.y += top_border;
1106 wxSize old_size( m_size );
1107 m_size.x -= 2*other_border;
1108 m_size.y -= top_border + other_border;
1109
1110 wxBoxSizer::RecalcSizes();
1111
1112 m_position = old_pos;
1113 m_size = old_size;
1114}
1115
1116wxSize wxStaticBoxSizer::CalcMin()
1117{
1118 int top_border, other_border;
1119 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1120
1121 wxSize ret( wxBoxSizer::CalcMin() );
1122 ret.x += 2*other_border;
1123 ret.y += other_border + top_border;
1124
1125 return ret;
1126}
1127
1128#endif // wxUSE_STATBOX
1129
1130//---------------------------------------------------------------------------
1131// wxNotebookSizer
1132//---------------------------------------------------------------------------
1133
1134#if wxUSE_NOTEBOOK
1135
1136wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
1137{
1138 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
1139
1140 m_notebook = nb;
1141}
1142
1143void wxNotebookSizer::RecalcSizes()
1144{
1145 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1146}
1147
1148wxSize wxNotebookSizer::CalcMin()
1149{
1150 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1151
1152 sizeBorder.x += 5;
1153 sizeBorder.y += 5;
1154
1155 if (m_notebook->GetChildren().GetCount() == 0)
1156 {
1157 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1158 }
1159
1160 int maxX = 0;
1161 int maxY = 0;
1162
1163 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1164 while (node)
1165 {
1166 wxWindow *item = node->GetData();
1167 wxSizer *itemsizer = item->GetSizer();
1168
1169 if (itemsizer)
1170 {
1171 wxSize subsize( itemsizer->CalcMin() );
1172
1173 if (subsize.x > maxX)
1174 maxX = subsize.x;
1175 if (subsize.y > maxY)
1176 maxY = subsize.y;
1177 }
1178
1179 node = node->GetNext();
1180 }
1181
1182 return wxSize( maxX, maxY ) + sizeBorder;
1183}
1184
1185#endif // wxUSE_NOTEBOOK