]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/sizer.cpp
Tweaked python image output slightly
[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: Ron Lee
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
403wxSize 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 return size;
414}
415
416void wxSizer::FitInside( wxWindow *window )
417{
418 wxSize size;
419 if (window->IsTopLevel())
420 size = VirtualFitSize( window );
421 else
422 size = GetMinClientSize( window );
423
424 window->SetVirtualSize( size );
425}
426
427void wxSizer::Layout()
428{
429 CalcMin();
430 RecalcSizes();
431}
432
433void wxSizer::SetSizeHints( wxWindow *window )
434{
435 // Preserve the window's max size hints, but set the
436 // lower bound according to the sizer calculations.
437
438 wxSize size = Fit( window );
439
440 window->SetSizeHints( size.x,
441 size.y,
442 window->GetMaxWidth(),
443 window->GetMaxHeight() );
444}
445
446void wxSizer::SetVirtualSizeHints( wxWindow *window )
447{
448 // Preserve the window's max size hints, but set the
449 // lower bound according to the sizer calculations.
450
451 FitInside( window );
452 wxSize size( window->GetVirtualSize() );
453 window->SetVirtualSizeHints( size.x,
454 size.y,
455 window->GetMaxWidth(),
456 window->GetMaxHeight() );
457}
458
459wxSize wxSizer::GetMaxWindowSize( wxWindow *window )
460{
461 return window->GetMaxSize();
462}
463
464wxSize wxSizer::GetMinWindowSize( wxWindow *window )
465{
466 wxSize minSize( GetMinSize() );
467 wxSize size( window->GetSize() );
468 wxSize client_size( window->GetClientSize() );
469 return wxSize( minSize.x+size.x-client_size.x,
470 minSize.y+size.y-client_size.y );
471}
472
473// Return a window size that will fit within the screens dimensions
474wxSize wxSizer::FitSize( wxWindow *window )
475{
476 wxSize size = GetMinWindowSize( window );
477 wxSize sizeMax = GetMaxWindowSize( window );
478
479 // Limit the size if sizeMax != wxDefaultSize
480
481 if ( size.x > sizeMax.x && sizeMax.x != -1 )
482 size.x = sizeMax.x;
483 if ( size.y > sizeMax.y && sizeMax.y != -1 )
484 size.y = sizeMax.y;
485
486 return size;
487}
488
489wxSize wxSizer::GetMaxClientSize( wxWindow *window )
490{
491 wxSize maxSize( window->GetMaxSize() );
492
493 if( maxSize != wxDefaultSize )
494 {
495 wxSize size( window->GetSize() );
496 wxSize client_size( window->GetClientSize() );
497
498 return wxSize( maxSize.x + client_size.x - size.x,
499 maxSize.y + client_size.y - size.y );
500 }
501 else
502 return wxDefaultSize;
503}
504
505wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
506{
507 return GetMinSize(); // Already returns client size.
508}
509
510wxSize wxSizer::VirtualFitSize( wxWindow *window )
511{
512 wxSize size = GetMinClientSize( window );
513 wxSize sizeMax = GetMaxClientSize( window );
514
515 // Limit the size if sizeMax != wxDefaultSize
516
517 if ( size.x > sizeMax.x && sizeMax.x != -1 )
518 size.x = sizeMax.x;
519 if ( size.y > sizeMax.y && sizeMax.y != -1 )
520 size.y = sizeMax.y;
521
522 return size;
523}
524
525void wxSizer::SetDimension( int x, int y, int width, int height )
526{
527 m_position.x = x;
528 m_position.y = y;
529 m_size.x = width;
530 m_size.y = height;
531 CalcMin();
532 RecalcSizes();
533}
534
535wxSize wxSizer::GetMinSize()
536{
537 wxSize ret( CalcMin() );
538 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
539 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
540 return ret;
541}
542
543void wxSizer::DoSetMinSize( int width, int height )
544{
545 m_minSize.x = width;
546 m_minSize.y = height;
547}
548
549bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
550{
551 wxASSERT( window );
552
553 wxNode *node = m_children.First();
554 while (node)
555 {
556 wxSizerItem *item = (wxSizerItem*)node->Data();
557 if (item->GetWindow() == window)
558 {
559 item->SetInitSize( width, height );
560 return TRUE;
561 }
562 node = node->Next();
563 }
564
565 node = m_children.First();
566 while (node)
567 {
568 wxSizerItem *item = (wxSizerItem*)node->Data();
569 if (item->GetSizer())
570 {
571 /* It's a sizer, so lets search recursively. */
572 if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
573 {
574 /* A child sizer found the requested windw, exit. */
575 return TRUE;
576 }
577 }
578 node = node->Next();
579 }
580
581 return FALSE;
582}
583
584bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
585{
586 wxASSERT( sizer );
587
588 wxNode *node = m_children.First();
589 while (node)
590 {
591 wxSizerItem *item = (wxSizerItem*)node->Data();
592 if (item->GetSizer() == sizer)
593 {
594 item->GetSizer()->DoSetMinSize( width, height );
595 return TRUE;
596 }
597 node = node->Next();
598 }
599
600 node = m_children.First();
601 while (node)
602 {
603 wxSizerItem *item = (wxSizerItem*)node->Data();
604 if (item->GetSizer())
605 {
606 /* It's a sizer, so lets search recursively. */
607 if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
608 {
609 /* A child sizer found the requested windw, exit. */
610 return TRUE;
611 }
612 }
613 node = node->Next();
614 }
615
616 return FALSE;
617}
618
619bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
620{
621 wxNode *node = m_children.Nth( pos );
622 if (!node) return FALSE;
623
624 wxSizerItem *item = (wxSizerItem*) node->Data();
625 if (item->GetSizer())
626 {
627 /* Sizers contains the minimal size in them, if not calculated ... */
628 item->GetSizer()->DoSetMinSize( width, height );
629 }
630 else
631 {
632 /* ... whereas the minimal size of spacers and windows in stored
633 in the item */
634 item->SetInitSize( width, height );
635 }
636
637 return TRUE;
638}
639
640//---------------------------------------------------------------------------
641// wxGridSizer
642//---------------------------------------------------------------------------
643
644wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
645{
646 m_rows = rows;
647 m_cols = cols;
648 m_vgap = vgap;
649 m_hgap = hgap;
650}
651
652wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
653{
654 m_rows = 0;
655 m_cols = cols;
656 m_vgap = vgap;
657 m_hgap = hgap;
658}
659
660void wxGridSizer::RecalcSizes()
661{
662 if (m_children.GetCount() == 0)
663 return;
664
665 int nitems = m_children.GetCount();
666 int nrows = m_rows;
667 int ncols = m_cols;
668
669 if (ncols > 0)
670 nrows = (nitems + ncols-1) / ncols;
671 else
672 ncols = (nitems + nrows-1) / nrows;
673
674 wxSize sz( GetSize() );
675 wxPoint pt( GetPosition() );
676
677 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
678 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
679
680 int x = pt.x;
681 for (int c = 0; c < ncols; c++)
682 {
683 int y = pt.y;
684 for (int r = 0; r < nrows; r++)
685 {
686 int i = r * ncols + c;
687 if (i < nitems)
688 {
689 wxNode *node = m_children.Nth( i );
690 wxASSERT( node );
691
692 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
693 }
694 y = y + h + m_vgap;
695 }
696 x = x + w + m_hgap;
697 }
698}
699
700wxSize wxGridSizer::CalcMin()
701{
702 if (m_children.GetCount() == 0)
703 return wxSize(10,10);
704
705 int nitems = m_children.GetCount();
706 int nrows = m_rows;
707 int ncols = m_cols;
708
709 if (ncols > 0)
710 nrows = (nitems + ncols-1) / ncols;
711 else
712 ncols = (nitems + nrows-1) / nrows;
713
714 // Find the max width and height for any component
715 int w = 0;
716 int h = 0;
717
718 wxNode *node = m_children.First();
719 while (node)
720 {
721 wxSizerItem *item = (wxSizerItem*)node->Data();
722 wxSize sz( item->CalcMin() );
723 w = wxMax( w, sz.x );
724 h = wxMax( h, sz.y );
725
726 node = node->Next();
727 }
728
729 return wxSize(ncols * w + (ncols-1) * m_hgap,
730 nrows * h + (nrows-1) * m_vgap);
731}
732
733void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
734{
735 wxPoint pt( x,y );
736 wxSize sz( item->CalcMin() );
737 int flag = item->GetFlag();
738
739 if ((flag & wxEXPAND) || (flag & wxSHAPED))
740 {
741 sz = wxSize(w, h);
742 }
743 else
744 {
745 if (flag & wxALIGN_CENTER_HORIZONTAL)
746 {
747 pt.x = x + (w - sz.x) / 2;
748 }
749 else if (flag & wxALIGN_RIGHT)
750 {
751 pt.x = x + (w - sz.x);
752 }
753
754 if (flag & wxALIGN_CENTER_VERTICAL)
755 {
756 pt.y = y + (h - sz.y) / 2;
757 }
758 else if (flag & wxALIGN_BOTTOM)
759 {
760 pt.y = y + (h - sz.y);
761 }
762 }
763
764 item->SetDimension(pt, sz);
765}
766
767//---------------------------------------------------------------------------
768// wxFlexGridSizer
769//---------------------------------------------------------------------------
770
771wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
772 : wxGridSizer( rows, cols, vgap, hgap )
773{
774 m_rowHeights = (int*) NULL;
775 m_colWidths = (int*) NULL;
776}
777
778wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
779 : wxGridSizer( cols, vgap, hgap )
780{
781 m_rowHeights = (int*) NULL;
782 m_colWidths = (int*) NULL;
783}
784
785wxFlexGridSizer::~wxFlexGridSizer()
786{
787 if (m_rowHeights)
788 delete[] m_rowHeights;
789 if (m_colWidths)
790 delete[] m_colWidths;
791}
792
793void wxFlexGridSizer::CreateArrays()
794{
795 if (m_rowHeights)
796 delete[] m_rowHeights;
797 if (m_colWidths)
798 delete[] m_colWidths;
799
800 if (m_children.GetCount() == 0)
801 return;
802
803 int nitems = m_children.GetCount();
804 int nrows = m_rows;
805 int ncols = m_cols;
806
807 if (ncols > 0)
808 nrows = (nitems + ncols-1) / ncols;
809 else
810 ncols = (nitems + nrows-1) / nrows;
811
812 m_rowHeights = new int[nrows];
813 m_colWidths = new int[ncols];
814
815 for (int col = 0; col < ncols; col++)
816 m_colWidths[ col ] = 0;
817 for (int row = 0; row < nrows; row++)
818 m_rowHeights[ row ] = 0;
819}
820
821void wxFlexGridSizer::RecalcSizes()
822{
823 if (m_children.GetCount() == 0)
824 return;
825
826 int nitems = m_children.GetCount();
827 int nrows = m_rows;
828 int ncols = m_cols;
829
830 if (ncols > 0)
831 nrows = (nitems + ncols-1) / ncols;
832 else
833 ncols = (nitems + nrows-1) / nrows;
834
835 wxSize sz( GetSize() );
836 wxSize minsz( CalcMin() );
837 wxPoint pt( GetPosition() );
838 int delta;
839 size_t idx,num;
840 wxArrayInt temp;
841
842 // Transfer only those rows into temp which exist in the sizer
843 // ignoring the superflouus ones. This prevents a segfault when
844 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
845 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
846 if (m_growableRows[idx] < nrows)
847 temp.Add( m_growableRows[idx] );
848 num = temp.GetCount();
849
850 if ((num > 0) && (sz.y > minsz.y))
851 {
852 delta = (sz.y - minsz.y) / num;
853 for (idx = 0; idx < num; idx++)
854 m_rowHeights[ temp[idx] ] += delta;
855 }
856
857 temp.Empty();
858 // See above
859 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
860 if (m_growableCols[idx] < ncols)
861 temp.Add( m_growableCols[idx] );
862 num = temp.GetCount();
863
864 if ((num > 0) && (sz.x > minsz.x))
865 {
866 delta = (sz.x - minsz.x) / num;
867 for (idx = 0; idx < num; idx++)
868 m_colWidths[ temp[idx] ] += delta;
869 }
870
871 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
872
873 int x = pt.x;
874 for (int c = 0; c < ncols; c++)
875 {
876 int y = pt.y;
877 for (int r = 0; r < nrows; r++)
878 {
879 int i = r * ncols + c;
880 if (i < nitems)
881 {
882 wxNode *node = m_children.Nth( i );
883 wxASSERT( node );
884
885 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
886 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
887
888 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
889 }
890 y = y + m_rowHeights[r] + m_vgap;
891 }
892 x = x + m_colWidths[c] + m_hgap;
893 }
894}
895
896wxSize wxFlexGridSizer::CalcMin()
897{
898 if (m_children.GetCount() == 0)
899 return wxSize(10,10);
900
901 int nitems = m_children.GetCount();
902 int nrows = m_rows;
903 int ncols = m_cols;
904
905 if (ncols > 0)
906 nrows = (nitems + ncols-1) / ncols;
907 else
908 ncols = (nitems + nrows-1) / nrows;
909
910 CreateArrays();
911
912 int col;
913 int row;
914
915 int i = 0;
916 wxNode *node = m_children.First();
917 while (node)
918 {
919 wxSizerItem *item = (wxSizerItem*)node->Data();
920 wxSize sz( item->CalcMin() );
921 row = i / ncols;
922 col = i % ncols;
923 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
924 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
925
926 node = node->Next();
927 i++;
928 }
929
930 int width = 0;
931 for (col = 0; col < ncols; col++)
932 width += m_colWidths[ col ];
933
934 int height = 0;
935 for (row = 0; row < nrows; row++)
936 height += m_rowHeights[ row ];
937
938 return wxSize( width + (ncols-1) * m_hgap,
939 height + (nrows-1) * m_vgap);
940}
941
942void wxFlexGridSizer::AddGrowableRow( size_t idx )
943{
944 m_growableRows.Add( idx );
945}
946
947void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
948{
949}
950
951void wxFlexGridSizer::AddGrowableCol( size_t idx )
952{
953 m_growableCols.Add( idx );
954}
955
956void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
957{
958}
959
960//---------------------------------------------------------------------------
961// wxBoxSizer
962//---------------------------------------------------------------------------
963
964wxBoxSizer::wxBoxSizer( int orient )
965{
966 m_orient = orient;
967}
968
969void wxBoxSizer::RecalcSizes()
970{
971 if (m_children.GetCount() == 0)
972 return;
973
974 int delta = 0;
975 int extra = 0;
976 if (m_stretchable)
977 {
978 if (m_orient == wxHORIZONTAL)
979 {
980 delta = (m_size.x - m_fixedWidth) / m_stretchable;
981 extra = (m_size.x - m_fixedWidth) % m_stretchable;
982 }
983 else
984 {
985 delta = (m_size.y - m_fixedHeight) / m_stretchable;
986 extra = (m_size.y - m_fixedHeight) % m_stretchable;
987 }
988 }
989
990 wxPoint pt( m_position );
991
992 wxNode *node = m_children.GetFirst();
993 while (node)
994 {
995 wxSizerItem *item = (wxSizerItem*) node->Data();
996
997 int weight = 1;
998 if (item->GetOption())
999 weight = item->GetOption();
1000
1001 wxSize size( item->CalcMin() );
1002
1003 if (m_orient == wxVERTICAL)
1004 {
1005 wxCoord height = size.y;
1006 if (item->GetOption())
1007 {
1008 height = (delta * weight) + extra;
1009 extra = 0; // only the first item will get the remainder as extra size
1010 }
1011
1012 wxPoint child_pos( pt );
1013 wxSize child_size( wxSize( size.x, height) );
1014
1015 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1016 child_size.x = m_size.x;
1017 else if (item->GetFlag() & wxALIGN_RIGHT)
1018 child_pos.x += m_size.x - size.x;
1019 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1020 // XXX wxCENTER is added for backward compatibility;
1021 // wxALIGN_CENTER should be used in new code
1022 child_pos.x += (m_size.x - size.x) / 2;
1023
1024 item->SetDimension( child_pos, child_size );
1025
1026 pt.y += height;
1027 }
1028 else
1029 {
1030 wxCoord width = size.x;
1031 if (item->GetOption())
1032 {
1033 width = (delta * weight) + extra;
1034 extra = 0; // only the first item will get the remainder as extra size
1035 }
1036
1037 wxPoint child_pos( pt );
1038 wxSize child_size( wxSize(width, size.y) );
1039
1040 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1041 child_size.y = m_size.y;
1042 else if (item->GetFlag() & wxALIGN_BOTTOM)
1043 child_pos.y += m_size.y - size.y;
1044 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1045 // XXX wxCENTER is added for backward compatibility;
1046 // wxALIGN_CENTER should be used in new code
1047 child_pos.y += (m_size.y - size.y) / 2;
1048
1049 item->SetDimension( child_pos, child_size );
1050
1051 pt.x += width;
1052 }
1053
1054 node = node->Next();
1055 }
1056}
1057
1058wxSize wxBoxSizer::CalcMin()
1059{
1060 if (m_children.GetCount() == 0)
1061 return wxSize(10,10);
1062
1063 m_stretchable = 0;
1064 m_minWidth = 0;
1065 m_minHeight = 0;
1066 m_fixedWidth = 0;
1067 m_fixedHeight = 0;
1068
1069 // Find how long each stretch unit needs to be
1070 int stretchSize = 1;
1071 wxNode *node = m_children.GetFirst();
1072 while (node)
1073 {
1074 wxSizerItem *item = (wxSizerItem*) node->Data();
1075 if (item->GetOption() != 0)
1076 {
1077 int stretch = item->GetOption();
1078 wxSize size( item->CalcMin() );
1079 int sizePerStretch;
1080 // Integer division rounded up is (a + b - 1) / b
1081 if (m_orient == wxHORIZONTAL)
1082 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1083 else
1084 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1085 if (sizePerStretch > stretchSize)
1086 stretchSize = sizePerStretch;
1087 }
1088 node = node->Next();
1089 }
1090 // Calculate overall minimum size
1091 node = m_children.GetFirst();
1092 while (node)
1093 {
1094 wxSizerItem *item = (wxSizerItem*) node->Data();
1095
1096 m_stretchable += item->GetOption();
1097
1098 wxSize size( item->CalcMin() );
1099 if (item->GetOption() != 0)
1100 {
1101 if (m_orient == wxHORIZONTAL)
1102 size.x = stretchSize * item->GetOption();
1103 else
1104 size.y = stretchSize * item->GetOption();
1105 }
1106
1107 if (m_orient == wxHORIZONTAL)
1108 {
1109 m_minWidth += size.x;
1110 m_minHeight = wxMax( m_minHeight, size.y );
1111 }
1112 else
1113 {
1114 m_minHeight += size.y;
1115 m_minWidth = wxMax( m_minWidth, size.x );
1116 }
1117
1118 if (item->GetOption() == 0)
1119 {
1120 if (m_orient == wxVERTICAL)
1121 {
1122 m_fixedHeight += size.y;
1123 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1124 }
1125 else
1126 {
1127 m_fixedWidth += size.x;
1128 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1129 }
1130 }
1131
1132 node = node->Next();
1133 }
1134
1135 return wxSize( m_minWidth, m_minHeight );
1136}
1137
1138//---------------------------------------------------------------------------
1139// wxStaticBoxSizer
1140//---------------------------------------------------------------------------
1141
1142#if wxUSE_STATBOX
1143
1144wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1145 : wxBoxSizer( orient )
1146{
1147 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1148
1149 m_staticBox = box;
1150}
1151
1152static void GetStaticBoxBorders(wxStaticBox *box,
1153 int *borderTop, int *borderOther)
1154{
1155 // this has to be done platform by platform as there is no way to
1156 // guess the thickness of a wxStaticBox border
1157#ifdef __WXGTK__
1158 if ( box->GetLabel().IsEmpty() )
1159 *borderTop = 5;
1160 else
1161#endif // __WXGTK__
1162 *borderTop = 15;
1163 (void)box;
1164 *borderOther = 5;
1165}
1166
1167void wxStaticBoxSizer::RecalcSizes()
1168{
1169 int top_border, other_border;
1170 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1171
1172 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1173
1174 wxPoint old_pos( m_position );
1175 m_position.x += other_border;
1176 m_position.y += top_border;
1177 wxSize old_size( m_size );
1178 m_size.x -= 2*other_border;
1179 m_size.y -= top_border + other_border;
1180
1181 wxBoxSizer::RecalcSizes();
1182
1183 m_position = old_pos;
1184 m_size = old_size;
1185}
1186
1187wxSize wxStaticBoxSizer::CalcMin()
1188{
1189 int top_border, other_border;
1190 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1191
1192 wxSize ret( wxBoxSizer::CalcMin() );
1193 ret.x += 2*other_border;
1194 ret.y += other_border + top_border;
1195
1196 return ret;
1197}
1198
1199#endif // wxUSE_STATBOX
1200
1201//---------------------------------------------------------------------------
1202// wxNotebookSizer
1203//---------------------------------------------------------------------------
1204
1205#if wxUSE_NOTEBOOK
1206
1207wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
1208{
1209 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
1210
1211 m_notebook = nb;
1212}
1213
1214void wxNotebookSizer::RecalcSizes()
1215{
1216 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1217}
1218
1219wxSize wxNotebookSizer::CalcMin()
1220{
1221 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1222
1223 sizeBorder.x += 5;
1224 sizeBorder.y += 5;
1225
1226 if (m_notebook->GetChildren().GetCount() == 0)
1227 {
1228 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1229 }
1230
1231 int maxX = 0;
1232 int maxY = 0;
1233
1234 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1235 while (node)
1236 {
1237 wxWindow *item = node->GetData();
1238 wxSizer *itemsizer = item->GetSizer();
1239
1240 if (itemsizer)
1241 {
1242 wxSize subsize( itemsizer->CalcMin() );
1243
1244 if (subsize.x > maxX)
1245 maxX = subsize.x;
1246 if (subsize.y > maxY)
1247 maxY = subsize.y;
1248 }
1249
1250 node = node->GetNext();
1251 }
1252
1253 return wxSize( maxX, maxY ) + sizeBorder;
1254}
1255
1256#endif // wxUSE_NOTEBOOK
1257
1258// vi:sts=4:sw=4:et