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