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