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