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