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