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