]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
post wxUniv fixes
[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 #if wxUSE_STATBOX
36 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer);
37 #endif
38 #if wxUSE_NOTEBOOK
39 IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer);
40 #endif
41
42 //---------------------------------------------------------------------------
43 // wxSizerItem
44 //---------------------------------------------------------------------------
45
46 wxSizerItem::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
65 wxSizerItem::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
84 wxSizerItem::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
101 wxSizerItem::~wxSizerItem()
102 {
103 if (m_userData)
104 delete m_userData;
105 if (m_sizer)
106 delete m_sizer;
107 }
108
109
110 wxSize 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
132 wxSize 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
173 void 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
235 bool wxSizerItem::IsWindow()
236 {
237 return (m_window != NULL);
238 }
239
240 bool wxSizerItem::IsSizer()
241 {
242 return (m_sizer != NULL);
243 }
244
245 bool wxSizerItem::IsSpacer()
246 {
247 return (m_window == NULL) && (m_sizer == NULL);
248 }
249
250 //---------------------------------------------------------------------------
251 // wxSizer
252 //---------------------------------------------------------------------------
253
254 wxSizer::wxSizer()
255 {
256 m_children.DeleteContents( TRUE );
257 m_minSize.x = 0;
258 m_minSize.y = 0;
259 }
260
261 wxSizer::~wxSizer()
262 {
263 }
264
265 void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
266 {
267 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
268 }
269
270 void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
271 {
272 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
273 }
274
275 void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
276 {
277 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
278 }
279
280 void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
281 {
282 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
283 }
284
285 void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
286 {
287 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
288 }
289
290 void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
291 {
292 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
293 }
294
295 void wxSizer::Insert( int before, wxWindow *window, int option, int flag, int border, wxObject* userData )
296 {
297 m_children.Insert( before, new wxSizerItem( window, option, flag, border, userData ) );
298 }
299
300 void wxSizer::Insert( int before, wxSizer *sizer, int option, int flag, int border, wxObject* userData )
301 {
302 m_children.Insert( before, new wxSizerItem( sizer, option, flag, border, userData ) );
303 }
304
305 void wxSizer::Insert( int before, int width, int height, int option, int flag, int border, wxObject* userData )
306 {
307 m_children.Insert( before, new wxSizerItem( width, height, option, flag, border, userData ) );
308 }
309
310 bool wxSizer::Remove( wxWindow *window )
311 {
312 wxASSERT( window );
313
314 wxNode *node = m_children.First();
315 while (node)
316 {
317 wxSizerItem *item = (wxSizerItem*)node->Data();
318 if (item->GetWindow() == window)
319 {
320 m_children.DeleteNode( node );
321 return TRUE;
322 }
323 node = node->Next();
324 }
325
326 return FALSE;
327 }
328
329 bool wxSizer::Remove( wxSizer *sizer )
330 {
331 wxASSERT( sizer );
332
333 wxNode *node = m_children.First();
334 while (node)
335 {
336 wxSizerItem *item = (wxSizerItem*)node->Data();
337 if (item->GetSizer() == sizer)
338 {
339 m_children.DeleteNode( node );
340 return TRUE;
341 }
342 node = node->Next();
343 }
344
345 return FALSE;
346 }
347
348 bool wxSizer::Remove( int pos )
349 {
350 wxNode *node = m_children.Nth( pos );
351 if (!node) return FALSE;
352
353 m_children.DeleteNode( node );
354
355 return TRUE;
356 }
357
358 void wxSizer::Fit( wxWindow *window )
359 {
360 wxSize size;
361 if (window->IsTopLevel())
362 size = FitSize( window );
363 else
364 size = GetMinWindowSize( window );
365
366 window->SetSize( size );
367 }
368
369 void wxSizer::Layout()
370 {
371 CalcMin();
372 RecalcSizes();
373 }
374
375 void wxSizer::SetSizeHints( wxWindow *window )
376 {
377 wxSize size = FitSize( window );
378 window->SetSizeHints( size.x, size.y );
379 }
380
381 wxSize wxSizer::GetMaxWindowSize( wxWindow *WXUNUSED(window) )
382 {
383 wxRect rect = wxGetClientDisplayRect();
384 wxSize sizeMax (rect.width,rect.height);
385
386 // Make the max size a bit smaller than the visible portion of
387 // the screen. A window which takes the entire screen doesn't
388 // look very nice either
389 sizeMax.x *= 9;
390 sizeMax.x /= 10;
391
392 sizeMax.y *= 9;
393 sizeMax.y /= 10;
394
395 return sizeMax;
396 }
397
398 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
399 {
400 wxSize minSize( GetMinSize() );
401 wxSize size( window->GetSize() );
402 wxSize client_size( window->GetClientSize() );
403 return wxSize( minSize.x+size.x-client_size.x,
404 minSize.y+size.y-client_size.y );
405 }
406
407 // Return a window size that will fit within the screens dimensions
408 wxSize wxSizer::FitSize( wxWindow *window )
409 {
410 wxSize size = GetMinWindowSize( window );
411 wxSize sizeMax = GetMaxWindowSize( window );
412
413 if ( size.x > sizeMax.x )
414 size.x = sizeMax.x;
415 if ( size.y > sizeMax.y )
416 size.y = sizeMax.y;
417
418 return size;
419 }
420
421 void wxSizer::SetDimension( int x, int y, int width, int height )
422 {
423 m_position.x = x;
424 m_position.y = y;
425 m_size.x = width;
426 m_size.y = height;
427 CalcMin();
428 RecalcSizes();
429 }
430
431 wxSize wxSizer::GetMinSize()
432 {
433 wxSize ret( CalcMin() );
434 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
435 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
436 return ret;
437 }
438
439 void wxSizer::DoSetMinSize( int width, int height )
440 {
441 m_minSize.x = width;
442 m_minSize.y = height;
443 }
444
445 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
446 {
447 wxASSERT( window );
448
449 wxNode *node = m_children.First();
450 while (node)
451 {
452 wxSizerItem *item = (wxSizerItem*)node->Data();
453 if (item->GetWindow() == window)
454 {
455 item->SetInitSize( width, height );
456 return TRUE;
457 }
458 node = node->Next();
459 }
460
461 node = m_children.First();
462 while (node)
463 {
464 wxSizerItem *item = (wxSizerItem*)node->Data();
465 if (item->GetSizer())
466 {
467 /* It's a sizer, so lets search recursively. */
468 if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
469 {
470 /* A child sizer found the requested windw, exit. */
471 return TRUE;
472 }
473 }
474 node = node->Next();
475 }
476
477 return FALSE;
478 }
479
480 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
481 {
482 wxASSERT( sizer );
483
484 wxNode *node = m_children.First();
485 while (node)
486 {
487 wxSizerItem *item = (wxSizerItem*)node->Data();
488 if (item->GetSizer() == sizer)
489 {
490 item->GetSizer()->DoSetMinSize( width, height );
491 return TRUE;
492 }
493 node = node->Next();
494 }
495
496 node = m_children.First();
497 while (node)
498 {
499 wxSizerItem *item = (wxSizerItem*)node->Data();
500 if (item->GetSizer())
501 {
502 /* It's a sizer, so lets search recursively. */
503 if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
504 {
505 /* A child sizer found the requested windw, exit. */
506 return TRUE;
507 }
508 }
509 node = node->Next();
510 }
511
512 return FALSE;
513 }
514
515 bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
516 {
517 wxNode *node = m_children.Nth( pos );
518 if (!node) return FALSE;
519
520 wxSizerItem *item = (wxSizerItem*) node->Data();
521 if (item->GetSizer())
522 {
523 /* Sizers contains the minimal size in them, if not calculated ... */
524 item->GetSizer()->DoSetMinSize( width, height );
525 }
526 else
527 {
528 /* ... whereas the minimal size of spacers and windows in stored
529 in the item */
530 item->SetInitSize( width, height );
531 }
532
533 return TRUE;
534 }
535
536 //---------------------------------------------------------------------------
537 // wxGridSizer
538 //---------------------------------------------------------------------------
539
540 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
541 {
542 m_rows = rows;
543 m_cols = cols;
544 m_vgap = vgap;
545 m_hgap = hgap;
546 }
547
548 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
549 {
550 m_rows = 0;
551 m_cols = cols;
552 m_vgap = vgap;
553 m_hgap = hgap;
554 }
555
556 void wxGridSizer::RecalcSizes()
557 {
558 if (m_children.GetCount() == 0)
559 return;
560
561 int nitems = m_children.GetCount();
562 int nrows = m_rows;
563 int ncols = m_cols;
564
565 if (ncols > 0)
566 nrows = (nitems + ncols-1) / ncols;
567 else
568 ncols = (nitems + nrows-1) / nrows;
569
570 wxSize sz( GetSize() );
571 wxPoint pt( GetPosition() );
572
573 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
574 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
575
576 int x = pt.x;
577 for (int c = 0; c < ncols; c++)
578 {
579 int y = pt.y;
580 for (int r = 0; r < nrows; r++)
581 {
582 int i = r * ncols + c;
583 if (i < nitems)
584 {
585 wxNode *node = m_children.Nth( i );
586 wxASSERT( node );
587
588 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
589 }
590 y = y + h + m_vgap;
591 }
592 x = x + w + m_hgap;
593 }
594 }
595
596 wxSize wxGridSizer::CalcMin()
597 {
598 if (m_children.GetCount() == 0)
599 return wxSize(10,10);
600
601 int nitems = m_children.GetCount();
602 int nrows = m_rows;
603 int ncols = m_cols;
604
605 if (ncols > 0)
606 nrows = (nitems + ncols-1) / ncols;
607 else
608 ncols = (nitems + nrows-1) / nrows;
609
610 /* Find the max width and height for any component */
611 int w = 0;
612 int h = 0;
613
614 wxNode *node = m_children.First();
615 while (node)
616 {
617 wxSizerItem *item = (wxSizerItem*)node->Data();
618 wxSize sz( item->CalcMin() );
619 w = wxMax( w, sz.x );
620 h = wxMax( h, sz.y );
621
622 node = node->Next();
623 }
624
625 return wxSize(ncols * w + (ncols-1) * m_hgap,
626 nrows * h + (nrows-1) * m_vgap);
627 }
628
629 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
630 {
631 wxPoint pt( x,y );
632 wxSize sz( item->CalcMin() );
633 int flag = item->GetFlag();
634
635 if ((flag & wxEXPAND) || (flag & wxSHAPED))
636 {
637 sz = wxSize(w, h);
638 }
639 else
640 {
641 if (flag & wxALIGN_CENTER_HORIZONTAL)
642 {
643 pt.x = x + (w - sz.x) / 2;
644 }
645 else if (flag & wxALIGN_RIGHT)
646 {
647 pt.x = x + (w - sz.x);
648 }
649
650 if (flag & wxALIGN_CENTER_VERTICAL)
651 {
652 pt.y = y + (h - sz.y) / 2;
653 }
654 else if (flag & wxALIGN_BOTTOM)
655 {
656 pt.y = y + (h - sz.y);
657 }
658 }
659
660 item->SetDimension(pt, sz);
661 }
662
663 //---------------------------------------------------------------------------
664 // wxFlexGridSizer
665 //---------------------------------------------------------------------------
666
667 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
668 : wxGridSizer( rows, cols, vgap, hgap )
669 {
670 m_rowHeights = (int*) NULL;
671 m_colWidths = (int*) NULL;
672 }
673
674 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
675 : wxGridSizer( cols, vgap, hgap )
676 {
677 m_rowHeights = (int*) NULL;
678 m_colWidths = (int*) NULL;
679 }
680
681 wxFlexGridSizer::~wxFlexGridSizer()
682 {
683 if (m_rowHeights)
684 delete[] m_rowHeights;
685 if (m_colWidths)
686 delete[] m_colWidths;
687 }
688
689 void wxFlexGridSizer::CreateArrays()
690 {
691 if (m_rowHeights)
692 delete[] m_rowHeights;
693 if (m_colWidths)
694 delete[] m_colWidths;
695
696 if (m_children.GetCount() == 0)
697 return;
698
699 int nitems = m_children.GetCount();
700 int nrows = m_rows;
701 int ncols = m_cols;
702
703 if (ncols > 0)
704 nrows = (nitems + ncols-1) / ncols;
705 else
706 ncols = (nitems + nrows-1) / nrows;
707
708 m_rowHeights = new int[nrows];
709 m_colWidths = new int[ncols];
710
711 for (int col = 0; col < ncols; col++)
712 m_colWidths[ col ] = 0;
713 for (int row = 0; row < nrows; row++)
714 m_rowHeights[ row ] = 0;
715 }
716
717 void wxFlexGridSizer::RecalcSizes()
718 {
719 if (m_children.GetCount() == 0)
720 return;
721
722 int nitems = m_children.GetCount();
723 int nrows = m_rows;
724 int ncols = m_cols;
725
726 if (ncols > 0)
727 nrows = (nitems + ncols-1) / ncols;
728 else
729 ncols = (nitems + nrows-1) / nrows;
730
731 wxSize sz( GetSize() );
732 wxSize minsz( CalcMin() );
733 wxPoint pt( GetPosition() );
734 int delta;
735 size_t idx;
736
737 if ((m_growableRows.GetCount() > 0) && (sz.y > minsz.y))
738 {
739 delta = (sz.y - minsz.y) / m_growableRows.GetCount();
740 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
741 m_rowHeights[ m_growableRows[idx] ] += delta;
742 }
743
744 if ((m_growableCols.GetCount() > 0) && (sz.x > minsz.x))
745 {
746 delta = (sz.x - minsz.x) / m_growableCols.GetCount();
747 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
748 m_colWidths[ m_growableCols[idx] ] += delta;
749 }
750
751 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
752
753 int x = pt.x;
754 for (int c = 0; c < ncols; c++)
755 {
756 int y = pt.y;
757 for (int r = 0; r < nrows; r++)
758 {
759 int i = r * ncols + c;
760 if (i < nitems)
761 {
762 wxNode *node = m_children.Nth( i );
763 wxASSERT( node );
764
765 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
766 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
767
768 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
769 }
770 y = y + m_rowHeights[r] + m_vgap;
771 }
772 x = x + m_colWidths[c] + m_hgap;
773 }
774 }
775
776 wxSize wxFlexGridSizer::CalcMin()
777 {
778 if (m_children.GetCount() == 0)
779 return wxSize(10,10);
780
781 int nitems = m_children.GetCount();
782 int nrows = m_rows;
783 int ncols = m_cols;
784
785 if (ncols > 0)
786 nrows = (nitems + ncols-1) / ncols;
787 else
788 ncols = (nitems + nrows-1) / nrows;
789
790 CreateArrays();
791
792 int col;
793 int row;
794
795 int i = 0;
796 wxNode *node = m_children.First();
797 while (node)
798 {
799 wxSizerItem *item = (wxSizerItem*)node->Data();
800 wxSize sz( item->CalcMin() );
801 row = i / ncols;
802 col = i % ncols;
803 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
804 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
805
806 node = node->Next();
807 i++;
808 }
809
810 int width = 0;
811 for (col = 0; col < ncols; col++)
812 width += m_colWidths[ col ];
813
814 int height = 0;
815 for (row = 0; row < nrows; row++)
816 height += m_rowHeights[ row ];
817
818 return wxSize( width + (ncols-1) * m_hgap,
819 height + (nrows-1) * m_vgap);
820 }
821
822 void wxFlexGridSizer::AddGrowableRow( size_t idx )
823 {
824 m_growableRows.Add( idx );
825 }
826
827 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
828 {
829 }
830
831 void wxFlexGridSizer::AddGrowableCol( size_t idx )
832 {
833 m_growableCols.Add( idx );
834 }
835
836 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
837 {
838 }
839
840 //---------------------------------------------------------------------------
841 // wxBoxSizer
842 //---------------------------------------------------------------------------
843
844 wxBoxSizer::wxBoxSizer( int orient )
845 {
846 m_orient = orient;
847 }
848
849 void wxBoxSizer::RecalcSizes()
850 {
851 if (m_children.GetCount() == 0)
852 return;
853
854 int delta = 0;
855 int extra = 0;
856 if (m_stretchable)
857 {
858 if (m_orient == wxHORIZONTAL)
859 {
860 delta = (m_size.x - m_fixedWidth) / m_stretchable;
861 extra = (m_size.x - m_fixedWidth) % m_stretchable;
862 }
863 else
864 {
865 delta = (m_size.y - m_fixedHeight) / m_stretchable;
866 extra = (m_size.y - m_fixedHeight) % m_stretchable;
867 }
868 }
869
870 wxPoint pt( m_position );
871
872 wxNode *node = m_children.GetFirst();
873 while (node)
874 {
875 wxSizerItem *item = (wxSizerItem*) node->Data();
876
877 int weight = 1;
878 if (item->GetOption())
879 weight = item->GetOption();
880
881 wxSize size( item->CalcMin() );
882
883 if (m_orient == wxVERTICAL)
884 {
885 wxCoord height = size.y;
886 if (item->GetOption())
887 {
888 height = (delta * weight) + extra;
889 extra = 0; // only the first item will get the remainder as extra size
890 }
891
892 wxPoint child_pos( pt );
893 wxSize child_size( wxSize( size.x, height) );
894
895 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
896 child_size.x = m_size.x;
897 else if (item->GetFlag() & wxALIGN_RIGHT)
898 child_pos.x += m_size.x - size.x;
899 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
900 // XXX wxCENTER is added for backward compatibility;
901 // wxALIGN_CENTER should be used in new code
902 child_pos.x += (m_size.x - size.x) / 2;
903
904 item->SetDimension( child_pos, child_size );
905
906 pt.y += height;
907 }
908 else
909 {
910 wxCoord width = size.x;
911 if (item->GetOption())
912 {
913 width = (delta * weight) + extra;
914 extra = 0; // only the first item will get the remainder as extra size
915 }
916
917 wxPoint child_pos( pt );
918 wxSize child_size( wxSize(width, size.y) );
919
920 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
921 child_size.y = m_size.y;
922 else if (item->GetFlag() & wxALIGN_BOTTOM)
923 child_pos.y += m_size.y - size.y;
924 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
925 // XXX wxCENTER is added for backward compatibility;
926 // wxALIGN_CENTER should be used in new code
927 child_pos.y += (m_size.y - size.y) / 2;
928
929 item->SetDimension( child_pos, child_size );
930
931 pt.x += width;
932 }
933
934 node = node->Next();
935 }
936 }
937
938 wxSize wxBoxSizer::CalcMin()
939 {
940 if (m_children.GetCount() == 0)
941 return wxSize(10,10);
942
943 m_stretchable = 0;
944 m_minWidth = 0;
945 m_minHeight = 0;
946 m_fixedWidth = 0;
947 m_fixedHeight = 0;
948
949 // Find how long each stretch unit needs to be
950 int stretchSize = 1;
951 wxNode *node = m_children.GetFirst();
952 while (node)
953 {
954 wxSizerItem *item = (wxSizerItem*) node->Data();
955 if (item->GetOption() != 0)
956 {
957 int stretch = item->GetOption();
958 wxSize size( item->CalcMin() );
959 int sizePerStretch;
960 // Integer division rounded up is (a + b - 1) / b
961 if (m_orient == wxHORIZONTAL)
962 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
963 else
964 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
965 if (sizePerStretch > stretchSize)
966 stretchSize = sizePerStretch;
967 }
968 node = node->Next();
969 }
970 // Calculate overall minimum size
971 node = m_children.GetFirst();
972 while (node)
973 {
974 wxSizerItem *item = (wxSizerItem*) node->Data();
975
976 m_stretchable += item->GetOption();
977
978 wxSize size( item->CalcMin() );
979 if (item->GetOption() != 0)
980 {
981 if (m_orient == wxHORIZONTAL)
982 size.x = stretchSize * item->GetOption();
983 else
984 size.y = stretchSize * item->GetOption();
985 }
986
987 if (m_orient == wxHORIZONTAL)
988 {
989 m_minWidth += size.x;
990 m_minHeight = wxMax( m_minHeight, size.y );
991 }
992 else
993 {
994 m_minHeight += size.y;
995 m_minWidth = wxMax( m_minWidth, size.x );
996 }
997
998 if (item->GetOption() == 0)
999 {
1000 if (m_orient == wxVERTICAL)
1001 {
1002 m_fixedHeight += size.y;
1003 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1004 }
1005 else
1006 {
1007 m_fixedWidth += size.x;
1008 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1009 }
1010 }
1011
1012 node = node->Next();
1013 }
1014
1015 return wxSize( m_minWidth, m_minHeight );
1016 }
1017
1018 //---------------------------------------------------------------------------
1019 // wxStaticBoxSizer
1020 //---------------------------------------------------------------------------
1021
1022 #if wxUSE_STATBOX
1023
1024 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1025 : wxBoxSizer( orient )
1026 {
1027 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1028
1029 m_staticBox = box;
1030 }
1031
1032 static void GetStaticBoxBorders(wxStaticBox *box,
1033 int *borderTop, int *borderOther)
1034 {
1035 // this has to be done platform by platform as there is no way to
1036 // guess the thickness of a wxStaticBox border
1037 #ifdef __WXGTK__
1038 if ( box->GetLabel().IsEmpty() )
1039 *borderTop = 5;
1040 else
1041 #endif // __WXGTK__
1042 *borderTop = 15;
1043 (void)box;
1044 *borderOther = 5;
1045 }
1046
1047 void wxStaticBoxSizer::RecalcSizes()
1048 {
1049 int top_border, other_border;
1050 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1051
1052 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1053
1054 wxPoint old_pos( m_position );
1055 m_position.x += other_border;
1056 m_position.y += top_border;
1057 wxSize old_size( m_size );
1058 m_size.x -= 2*other_border;
1059 m_size.y -= top_border + other_border;
1060
1061 wxBoxSizer::RecalcSizes();
1062
1063 m_position = old_pos;
1064 m_size = old_size;
1065 }
1066
1067 wxSize wxStaticBoxSizer::CalcMin()
1068 {
1069 int top_border, other_border;
1070 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1071
1072 wxSize ret( wxBoxSizer::CalcMin() );
1073 ret.x += 2*other_border;
1074 ret.y += other_border + top_border;
1075
1076 return ret;
1077 }
1078
1079 #endif // wxUSE_STATBOX
1080
1081 //---------------------------------------------------------------------------
1082 // wxNotebookSizer
1083 //---------------------------------------------------------------------------
1084
1085 #if wxUSE_NOTEBOOK
1086
1087 wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
1088 {
1089 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
1090
1091 m_notebook = nb;
1092 }
1093
1094 void wxNotebookSizer::RecalcSizes()
1095 {
1096 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1097 }
1098
1099 wxSize wxNotebookSizer::CalcMin()
1100 {
1101 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1102
1103 sizeBorder.x += 5;
1104 sizeBorder.y += 5;
1105
1106 if (m_notebook->GetChildren().GetCount() == 0)
1107 {
1108 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1109 }
1110
1111 int maxX = 0;
1112 int maxY = 0;
1113
1114 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1115 while (node)
1116 {
1117 wxWindow *item = node->GetData();
1118 wxSizer *itemsizer = item->GetSizer();
1119
1120 if (itemsizer)
1121 {
1122 wxSize subsize( itemsizer->CalcMin() );
1123
1124 if (subsize.x > maxX)
1125 maxX = subsize.x;
1126 if (subsize.y > maxY)
1127 maxY = subsize.y;
1128 }
1129
1130 node = node->GetNext();
1131 }
1132
1133 return wxSize( maxX, maxY ) + sizeBorder;
1134 }
1135
1136 #endif // wxUSE_NOTEBOOK