]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
made the #error message less self-contradictory
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: sizer.cpp
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn
5 // Modified by: Ron Lee
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "sizer.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/sizer.h"
24 #include "wx/utils.h"
25 #include "wx/statbox.h"
26 #include "wx/notebook.h"
27
28 //---------------------------------------------------------------------------
29
30 IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject)
31 IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject)
32 IMPLEMENT_ABSTRACT_CLASS(wxGridSizer, wxSizer)
33 IMPLEMENT_ABSTRACT_CLASS(wxFlexGridSizer, wxGridSizer)
34 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer)
35 #if wxUSE_STATBOX
36 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer)
37 #endif
38 #if wxUSE_NOTEBOOK
39 IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer)
40 #endif
41
42 //---------------------------------------------------------------------------
43 // wxSizerItem
44 //---------------------------------------------------------------------------
45
46 wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
47 : m_window( 0 )
48 , m_sizer( 0 )
49 , m_size( wxSize( width, height ) ) // size is set directly
50 , m_minSize( m_size ) // minimal size is the initial size
51 , m_option( option )
52 , m_border( border )
53 , m_flag( flag )
54 , m_show( TRUE ) // Cannot be changed
55 , m_userData( userData )
56 {
57 SetRatio( m_size );
58 }
59
60 wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
61 : m_window( window )
62 , m_sizer( 0 )
63 , m_minSize( window->GetSize() ) // minimal size is the initial size
64 , m_option( option )
65 , m_border( border )
66 , m_flag( flag )
67 , m_show( TRUE )
68 , m_userData( userData )
69 {
70 // aspect ratio calculated from initial size
71 SetRatio( m_minSize );
72
73 // m_size is calculated later
74 }
75
76 wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
77 : m_window( 0 )
78 , m_sizer( sizer )
79 , m_option( option )
80 , m_border( border )
81 , m_flag( flag )
82 , m_show( TRUE )
83 , m_ratio( 0 )
84 , m_userData( userData )
85 {
86 // m_minSize is calculated later
87 // m_size is calculated later
88 }
89
90 wxSizerItem::~wxSizerItem()
91 {
92 if (m_userData)
93 delete m_userData;
94 if (m_sizer)
95 delete m_sizer;
96 }
97
98
99 wxSize wxSizerItem::GetSize()
100 {
101 wxSize ret;
102 if (IsSizer())
103 ret = m_sizer->GetSize();
104 else
105 if (IsWindow())
106 ret = m_window->GetSize();
107 else ret = m_size;
108
109 if (m_flag & wxWEST)
110 ret.x += m_border;
111 if (m_flag & wxEAST)
112 ret.x += m_border;
113 if (m_flag & wxNORTH)
114 ret.y += m_border;
115 if (m_flag & wxSOUTH)
116 ret.y += m_border;
117
118 return ret;
119 }
120
121 wxSize wxSizerItem::CalcMin()
122 {
123 wxSize ret;
124 if (IsSizer())
125 {
126 ret = m_sizer->GetMinSize();
127
128 // if we have to preserve aspect ratio _AND_ this is
129 // the first-time calculation, consider ret to be initial size
130 if ((m_flag & wxSHAPED) && !m_ratio)
131 SetRatio(ret);
132 }
133 else
134 {
135 if ( IsWindow() && (m_flag & wxADJUST_MINSIZE) )
136 {
137 // By user request, keep the minimal size for this item
138 // in sync with the largest of BestSize and any user supplied
139 // minimum size hint. Useful in cases where the item is
140 // changeable -- static text labels, etc.
141 m_minSize = m_window->GetAdjustedBestSize();
142 }
143
144 ret = m_minSize;
145 }
146
147 if (m_flag & wxWEST)
148 ret.x += m_border;
149 if (m_flag & wxEAST)
150 ret.x += m_border;
151 if (m_flag & wxNORTH)
152 ret.y += m_border;
153 if (m_flag & wxSOUTH)
154 ret.y += m_border;
155
156 return ret;
157 }
158
159 void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
160 {
161 if (m_flag & wxSHAPED)
162 {
163 // adjust aspect ratio
164 int rwidth = (int) (size.y * m_ratio);
165 if (rwidth > size.x)
166 {
167 // fit horizontally
168 int rheight = (int) (size.x / m_ratio);
169 // add vertical space
170 if (m_flag & wxALIGN_CENTER_VERTICAL)
171 pos.y += (size.y - rheight) / 2;
172 else if (m_flag & wxALIGN_BOTTOM)
173 pos.y += (size.y - rheight);
174 // use reduced dimensions
175 size.y =rheight;
176 }
177 else if (rwidth < size.x)
178 {
179 // add horizontal space
180 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
181 pos.x += (size.x - rwidth) / 2;
182 else if (m_flag & wxALIGN_RIGHT)
183 pos.x += (size.x - rwidth);
184 size.x = rwidth;
185 }
186 }
187
188 // This is what GetPosition() returns. Since we calculate
189 // borders afterwards, GetPosition() will be the left/top
190 // corner of the surrounding border.
191 m_pos = pos;
192
193 if (m_flag & wxWEST)
194 {
195 pos.x += m_border;
196 size.x -= m_border;
197 }
198 if (m_flag & wxEAST)
199 {
200 size.x -= m_border;
201 }
202 if (m_flag & wxNORTH)
203 {
204 pos.y += m_border;
205 size.y -= m_border;
206 }
207 if (m_flag & wxSOUTH)
208 {
209 size.y -= m_border;
210 }
211
212 if (IsSizer())
213 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
214
215 if (IsWindow())
216 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
217
218 m_size = size;
219 }
220
221 void wxSizerItem::DeleteWindows()
222 {
223 if (m_window)
224 m_window->Destroy();
225
226 if (m_sizer)
227 m_sizer->DeleteWindows();
228 }
229
230 bool wxSizerItem::IsWindow()
231 {
232 return (m_window != NULL);
233 }
234
235 bool wxSizerItem::IsSizer()
236 {
237 return (m_sizer != NULL);
238 }
239
240 bool wxSizerItem::IsSpacer()
241 {
242 return (m_window == NULL) && (m_sizer == NULL);
243 }
244
245 //---------------------------------------------------------------------------
246 // wxSizer
247 //---------------------------------------------------------------------------
248
249 wxSizer::wxSizer()
250 {
251 m_children.DeleteContents( TRUE );
252 m_minSize.x = 0;
253 m_minSize.y = 0;
254 }
255
256 wxSizer::~wxSizer()
257 {
258 Clear();
259 }
260
261 void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
262 {
263 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
264 window->SetContainingSizer(this);
265 }
266
267 void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
268 {
269 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
270 }
271
272 void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
273 {
274 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
275 }
276
277 void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
278 {
279 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
280 window->SetContainingSizer(this);
281 }
282
283 void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
284 {
285 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
286 }
287
288 void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
289 {
290 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
291 }
292
293 void wxSizer::Insert( int before, wxWindow *window, int option, int flag, int border, wxObject* userData )
294 {
295 m_children.Insert( before, new wxSizerItem( window, option, flag, border, userData ) );
296 window->SetContainingSizer(this);
297 }
298
299 void wxSizer::Insert( int before, wxSizer *sizer, int option, int flag, int border, wxObject* userData )
300 {
301 m_children.Insert( before, new wxSizerItem( sizer, option, flag, border, userData ) );
302 }
303
304 void wxSizer::Insert( int before, int width, int height, int option, int flag, int border, wxObject* userData )
305 {
306 m_children.Insert( before, new wxSizerItem( width, height, option, flag, border, userData ) );
307 }
308
309 bool wxSizer::Remove( wxWindow *window )
310 {
311 wxASSERT( window );
312
313 wxNode *node = m_children.First();
314 while (node)
315 {
316 wxSizerItem *item = (wxSizerItem*)node->Data();
317 if (item->GetWindow() == window)
318 {
319 item->GetWindow()->SetContainingSizer(NULL);
320 m_children.DeleteNode( node );
321 return TRUE;
322 }
323 node = node->Next();
324 }
325
326 return FALSE;
327 }
328
329 bool wxSizer::Remove( wxSizer *sizer )
330 {
331 wxASSERT( sizer );
332
333 wxNode *node = m_children.First();
334 while (node)
335 {
336 wxSizerItem *item = (wxSizerItem*)node->Data();
337 if (item->GetSizer() == sizer)
338 {
339 m_children.DeleteNode( node );
340 return TRUE;
341 }
342 node = node->Next();
343 }
344
345 return FALSE;
346 }
347
348 bool wxSizer::Remove( int pos )
349 {
350 if ((size_t)pos >= m_children.GetCount())
351 return FALSE;
352 wxNode *node = m_children.Nth( pos );
353 if (!node) return FALSE;
354
355 m_children.DeleteNode( node );
356
357 return TRUE;
358 }
359
360 bool wxSizer::Detach( wxSizer *sizer )
361 {
362 wxASSERT( sizer );
363
364 wxNode *node = m_children.First();
365 while (node)
366 {
367 wxSizerItem *item = (wxSizerItem*)node->Data();
368 if (item->GetSizer() == sizer)
369 {
370 item->DetachSizer();
371 m_children.DeleteNode( node );
372 return TRUE;
373 }
374 node = node->Next();
375 }
376
377 return FALSE;
378 }
379
380 bool wxSizer::Detach( int pos )
381 {
382 if ((size_t)pos >= m_children.GetCount())
383 return FALSE;
384 wxNode *node = m_children.Nth( pos );
385 if (!node) return FALSE;
386
387 ( (wxSizerItem*)node->Data() )->DetachSizer();
388 m_children.DeleteNode( node );
389
390 return TRUE;
391 }
392
393 void wxSizer::Clear( bool delete_windows )
394 {
395 // First clear the ContainingSizer pointers
396 wxNode *node = m_children.First();
397 while (node)
398 {
399 wxSizerItem *item = (wxSizerItem*)node->Data();
400 if (item->IsWindow())
401 item->GetWindow()->SetContainingSizer(NULL);
402 node = node->Next();
403 }
404
405 // Destroy the windows if needed
406 if (delete_windows)
407 DeleteWindows();
408
409 // Now empty the list
410 m_children.Clear();
411 }
412
413 void wxSizer::DeleteWindows()
414 {
415 wxNode *node = m_children.First();
416 while (node)
417 {
418 wxSizerItem *item = (wxSizerItem*)node->Data();
419 item->DeleteWindows();
420 node = node->Next();
421 }
422 }
423
424 wxSize wxSizer::Fit( wxWindow *window )
425 {
426 wxSize size;
427 if (window->IsTopLevel())
428 size = FitSize( window );
429 else
430 size = GetMinWindowSize( window );
431
432 window->SetSize( size );
433
434 return size;
435 }
436
437 void wxSizer::FitInside( wxWindow *window )
438 {
439 wxSize size;
440 if (window->IsTopLevel())
441 size = VirtualFitSize( window );
442 else
443 size = GetMinClientSize( window );
444
445 window->SetVirtualSize( size );
446 }
447
448 void wxSizer::Layout()
449 {
450 CalcMin();
451 RecalcSizes();
452 }
453
454 void wxSizer::SetSizeHints( wxWindow *window )
455 {
456 // Preserve the window's max size hints, but set the
457 // lower bound according to the sizer calculations.
458
459 wxSize size = Fit( window );
460
461 window->SetSizeHints( size.x,
462 size.y,
463 window->GetMaxWidth(),
464 window->GetMaxHeight() );
465 }
466
467 void wxSizer::SetVirtualSizeHints( wxWindow *window )
468 {
469 // Preserve the window's max size hints, but set the
470 // lower bound according to the sizer calculations.
471
472 FitInside( window );
473 wxSize size( window->GetVirtualSize() );
474 window->SetVirtualSizeHints( size.x,
475 size.y,
476 window->GetMaxWidth(),
477 window->GetMaxHeight() );
478 }
479
480 wxSize wxSizer::GetMaxWindowSize( wxWindow *window )
481 {
482 return window->GetMaxSize();
483 }
484
485 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
486 {
487 wxSize minSize( GetMinSize() );
488 wxSize size( window->GetSize() );
489 wxSize client_size( window->GetClientSize() );
490 return wxSize( minSize.x+size.x-client_size.x,
491 minSize.y+size.y-client_size.y );
492 }
493
494 // Return a window size that will fit within the screens dimensions
495 wxSize wxSizer::FitSize( wxWindow *window )
496 {
497 wxSize size = GetMinWindowSize( window );
498 wxSize sizeMax = GetMaxWindowSize( window );
499
500 // Limit the size if sizeMax != wxDefaultSize
501
502 if ( size.x > sizeMax.x && sizeMax.x != -1 )
503 size.x = sizeMax.x;
504 if ( size.y > sizeMax.y && sizeMax.y != -1 )
505 size.y = sizeMax.y;
506
507 return size;
508 }
509
510 wxSize wxSizer::GetMaxClientSize( wxWindow *window )
511 {
512 wxSize maxSize( window->GetMaxSize() );
513
514 if( maxSize != wxDefaultSize )
515 {
516 wxSize size( window->GetSize() );
517 wxSize client_size( window->GetClientSize() );
518
519 return wxSize( maxSize.x + client_size.x - size.x,
520 maxSize.y + client_size.y - size.y );
521 }
522 else
523 return wxDefaultSize;
524 }
525
526 wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) )
527 {
528 return GetMinSize(); // Already returns client size.
529 }
530
531 wxSize wxSizer::VirtualFitSize( wxWindow *window )
532 {
533 wxSize size = GetMinClientSize( window );
534 wxSize sizeMax = GetMaxClientSize( window );
535
536 // Limit the size if sizeMax != wxDefaultSize
537
538 if ( size.x > sizeMax.x && sizeMax.x != -1 )
539 size.x = sizeMax.x;
540 if ( size.y > sizeMax.y && sizeMax.y != -1 )
541 size.y = sizeMax.y;
542
543 return size;
544 }
545
546 void wxSizer::SetDimension( int x, int y, int width, int height )
547 {
548 m_position.x = x;
549 m_position.y = y;
550 m_size.x = width;
551 m_size.y = height;
552 Layout();
553 }
554
555 wxSize wxSizer::GetMinSize()
556 {
557 wxSize ret( CalcMin() );
558 if (ret.x < m_minSize.x) ret.x = m_minSize.x;
559 if (ret.y < m_minSize.y) ret.y = m_minSize.y;
560 return ret;
561 }
562
563 void wxSizer::DoSetMinSize( int width, int height )
564 {
565 m_minSize.x = width;
566 m_minSize.y = height;
567 }
568
569 bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height )
570 {
571 wxASSERT( window );
572
573 wxNode *node = m_children.First();
574 while (node)
575 {
576 wxSizerItem *item = (wxSizerItem*)node->Data();
577 if (item->GetWindow() == window)
578 {
579 item->SetInitSize( width, height );
580 return TRUE;
581 }
582 node = node->Next();
583 }
584
585 node = m_children.First();
586 while (node)
587 {
588 wxSizerItem *item = (wxSizerItem*)node->Data();
589 if (item->GetSizer())
590 {
591 // It's a sizer, so lets search recursively.
592 if (item->GetSizer()->DoSetItemMinSize( window, width, height ))
593 {
594 // A child sizer found the requested windw, exit.
595 return TRUE;
596 }
597 }
598 node = node->Next();
599 }
600
601 return FALSE;
602 }
603
604 bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height )
605 {
606 wxASSERT( sizer );
607
608 wxNode *node = m_children.First();
609 while (node)
610 {
611 wxSizerItem *item = (wxSizerItem*)node->Data();
612 if (item->GetSizer() == sizer)
613 {
614 item->GetSizer()->DoSetMinSize( width, height );
615 return TRUE;
616 }
617 node = node->Next();
618 }
619
620 node = m_children.First();
621 while (node)
622 {
623 wxSizerItem *item = (wxSizerItem*)node->Data();
624 if (item->GetSizer())
625 {
626 // It's a sizer, so lets search recursively.
627 if (item->GetSizer()->DoSetItemMinSize( sizer, width, height ))
628 {
629 // A child sizer found the requested windw, exit.
630 return TRUE;
631 }
632 }
633 node = node->Next();
634 }
635
636 return FALSE;
637 }
638
639 bool wxSizer::DoSetItemMinSize( int pos, int width, int height )
640 {
641 wxNode *node = m_children.Nth( pos );
642 if (!node) return FALSE;
643
644 wxSizerItem *item = (wxSizerItem*) node->Data();
645 if (item->GetSizer())
646 {
647 // Sizers contains the minimal size in them, if not calculated ...
648 item->GetSizer()->DoSetMinSize( width, height );
649 }
650 else
651 {
652 // ... but the minimal size of spacers and windows in stored in them
653 item->SetInitSize( width, height );
654 }
655
656 return TRUE;
657 }
658
659 void wxSizer::Show(wxWindow *window, bool show)
660 {
661 wxNode *node = m_children.GetFirst();
662 while (node)
663 {
664 wxSizerItem *item = (wxSizerItem*) node->Data();
665
666 if (item->IsWindow() && item->GetWindow() == window)
667 {
668 item->Show(show);
669 window->Show(show);
670 return;
671 }
672 node = node->Next();
673 }
674 }
675
676 void wxSizer::Show(wxSizer *sizer, bool show)
677 {
678 wxNode *node = m_children.GetFirst();
679 while (node)
680 {
681 wxSizerItem *item = (wxSizerItem*) node->Data();
682
683 if (item->IsSizer() && item->GetSizer() == sizer)
684 {
685 item->Show(show);
686 sizer->ShowItems(show);
687 return;
688 }
689 node = node->Next();
690 }
691 }
692
693 void wxSizer::ShowItems (bool show)
694 {
695 wxNode *node = m_children.GetFirst();
696 while (node)
697 {
698 wxSizerItem *item = (wxSizerItem*) node->Data();
699
700 if (item->IsWindow())
701 item->GetWindow()->Show (show);
702 else if (item->IsSizer())
703 item->GetSizer()->ShowItems (show);
704
705 node = node->Next();
706 }
707 }
708
709 bool wxSizer::IsShown (wxWindow *window)
710 {
711 wxNode *node = m_children.GetFirst();
712 while (node)
713 {
714 wxSizerItem *item = (wxSizerItem*) node->Data();
715
716 if (item->IsWindow() && item->GetWindow() == window)
717 {
718 return item->IsShown();
719 }
720 node = node->Next();
721 }
722
723 return FALSE;
724 }
725
726 bool wxSizer::IsShown (wxSizer *sizer)
727 {
728 wxNode *node = m_children.GetFirst();
729 while (node)
730 {
731 wxSizerItem *item = (wxSizerItem*) node->Data();
732
733 if (item->IsSizer() && item->GetSizer() == sizer)
734 {
735 return item->IsShown();
736 }
737 node = node->Next();
738 }
739
740 return FALSE;
741 }
742
743 //---------------------------------------------------------------------------
744 // wxGridSizer
745 //---------------------------------------------------------------------------
746
747 wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap )
748 {
749 m_rows = rows;
750 m_cols = cols;
751 m_vgap = vgap;
752 m_hgap = hgap;
753 }
754
755 wxGridSizer::wxGridSizer( int cols, int vgap, int hgap )
756 {
757 m_rows = 0;
758 m_cols = cols;
759 m_vgap = vgap;
760 m_hgap = hgap;
761 }
762
763 int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const
764 {
765 int nitems = m_children.GetCount();
766 if ( nitems)
767 {
768 if ( m_cols )
769 {
770 ncols = m_cols;
771 nrows = (nitems + m_cols - 1) / m_cols;
772 }
773 else if ( m_rows )
774 {
775 ncols = (nitems + m_rows - 1) / m_rows;
776 nrows = m_rows;
777 }
778 else // 0 columns, 0 rows?
779 {
780 wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") );
781
782 nrows = ncols = 0;
783 }
784 }
785
786 return nitems;
787 }
788
789 void wxGridSizer::RecalcSizes()
790 {
791 int nitems, nrows, ncols;
792 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
793 return;
794
795 wxSize sz( GetSize() );
796 wxPoint pt( GetPosition() );
797
798 int w = (sz.x - (ncols - 1) * m_hgap) / ncols;
799 int h = (sz.y - (nrows - 1) * m_vgap) / nrows;
800
801 int x = pt.x;
802 for (int c = 0; c < ncols; c++)
803 {
804 int y = pt.y;
805 for (int r = 0; r < nrows; r++)
806 {
807 int i = r * ncols + c;
808 if (i < nitems)
809 {
810 wxNode *node = m_children.Nth( i );
811 wxASSERT( node );
812
813 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
814 }
815 y = y + h + m_vgap;
816 }
817 x = x + w + m_hgap;
818 }
819 }
820
821 wxSize wxGridSizer::CalcMin()
822 {
823 int nitems, nrows, ncols;
824 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
825 return wxSize(10, 10);
826
827 // Find the max width and height for any component
828 int w = 0;
829 int h = 0;
830
831 wxNode *node = m_children.First();
832 while (node)
833 {
834 wxSizerItem *item = (wxSizerItem*)node->Data();
835 wxSize sz( item->CalcMin() );
836 w = wxMax( w, sz.x );
837 h = wxMax( h, sz.y );
838
839 node = node->Next();
840 }
841
842 return wxSize(ncols * w + (ncols-1) * m_hgap,
843 nrows * h + (nrows-1) * m_vgap);
844 }
845
846 void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h )
847 {
848 wxPoint pt( x,y );
849 wxSize sz( item->CalcMin() );
850 int flag = item->GetFlag();
851
852 if ((flag & wxEXPAND) || (flag & wxSHAPED))
853 {
854 sz = wxSize(w, h);
855 }
856 else
857 {
858 if (flag & wxALIGN_CENTER_HORIZONTAL)
859 {
860 pt.x = x + (w - sz.x) / 2;
861 }
862 else if (flag & wxALIGN_RIGHT)
863 {
864 pt.x = x + (w - sz.x);
865 }
866
867 if (flag & wxALIGN_CENTER_VERTICAL)
868 {
869 pt.y = y + (h - sz.y) / 2;
870 }
871 else if (flag & wxALIGN_BOTTOM)
872 {
873 pt.y = y + (h - sz.y);
874 }
875 }
876
877 item->SetDimension(pt, sz);
878 }
879
880 //---------------------------------------------------------------------------
881 // wxFlexGridSizer
882 //---------------------------------------------------------------------------
883
884 wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap )
885 : wxGridSizer( rows, cols, vgap, hgap )
886 {
887 m_rowHeights = (int*) NULL;
888 m_colWidths = (int*) NULL;
889 }
890
891 wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap )
892 : wxGridSizer( cols, vgap, hgap )
893 {
894 m_rowHeights = (int*) NULL;
895 m_colWidths = (int*) NULL;
896 }
897
898 wxFlexGridSizer::~wxFlexGridSizer()
899 {
900 if (m_rowHeights)
901 delete[] m_rowHeights;
902 if (m_colWidths)
903 delete[] m_colWidths;
904 }
905
906 void wxFlexGridSizer::CreateArrays()
907 {
908 if (m_rowHeights)
909 delete[] m_rowHeights;
910 if (m_colWidths)
911 delete[] m_colWidths;
912
913 int nitems, nrows, ncols;
914 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
915 {
916 m_rowHeights =
917 m_colWidths = NULL;
918 }
919
920 m_rowHeights = new int[nrows];
921 m_colWidths = new int[ncols];
922
923 for (int col = 0; col < ncols; col++)
924 m_colWidths[ col ] = 0;
925 for (int row = 0; row < nrows; row++)
926 m_rowHeights[ row ] = 0;
927 }
928
929 void wxFlexGridSizer::RecalcSizes()
930 {
931 int nitems, nrows, ncols;
932 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
933 return;
934
935 wxSize sz( GetSize() );
936 wxSize minsz( CalcMin() );
937 wxPoint pt( GetPosition() );
938 int delta;
939 size_t idx,num;
940 wxArrayInt temp;
941
942 // Transfer only those rows into temp which exist in the sizer
943 // ignoring the superflouus ones. This prevents a segfault when
944 // calling AddGrowableRow( 3 ) if the sizer only has 2 rows.
945 for (idx = 0; idx < m_growableRows.GetCount(); idx++)
946 if (m_growableRows[idx] < nrows)
947 temp.Add( m_growableRows[idx] );
948 num = temp.GetCount();
949
950 if ((num > 0) && (sz.y > minsz.y))
951 {
952 delta = (sz.y - minsz.y) / num;
953 for (idx = 0; idx < num; idx++)
954 m_rowHeights[ temp[idx] ] += delta;
955 }
956
957 temp.Empty();
958 // See above
959 for (idx = 0; idx < m_growableCols.GetCount(); idx++)
960 if (m_growableCols[idx] < ncols)
961 temp.Add( m_growableCols[idx] );
962 num = temp.GetCount();
963
964 if ((num > 0) && (sz.x > minsz.x))
965 {
966 delta = (sz.x - minsz.x) / num;
967 for (idx = 0; idx < num; idx++)
968 m_colWidths[ temp[idx] ] += delta;
969 }
970
971 sz = wxSize( pt.x + sz.x, pt.y + sz.y );
972
973 int x = pt.x;
974 for (int c = 0; c < ncols; c++)
975 {
976 int y = pt.y;
977 for (int r = 0; r < nrows; r++)
978 {
979 int i = r * ncols + c;
980 if (i < nitems)
981 {
982 wxNode *node = m_children.Nth( i );
983 wxASSERT( node );
984
985 int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) );
986 int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) );
987
988 SetItemBounds( (wxSizerItem*) node->Data(), x, y, w, h);
989 }
990 y = y + m_rowHeights[r] + m_vgap;
991 }
992 x = x + m_colWidths[c] + m_hgap;
993 }
994 }
995
996 wxSize wxFlexGridSizer::CalcMin()
997 {
998 int nitems, nrows, ncols;
999 if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 )
1000 return wxSize(10,10);
1001
1002 CreateArrays();
1003
1004 int i = 0;
1005 wxNode *node = m_children.First();
1006 while (node)
1007 {
1008 wxSizerItem *item = (wxSizerItem*)node->Data();
1009 wxSize sz( item->CalcMin() );
1010 int row = i / ncols;
1011 int col = i % ncols;
1012 m_rowHeights[ row ] = wxMax( sz.y, m_rowHeights[ row ] );
1013 m_colWidths[ col ] = wxMax( sz.x, m_colWidths[ col ] );
1014
1015 node = node->Next();
1016 i++;
1017 }
1018
1019 int width = 0;
1020 for (int col = 0; col < ncols; col++)
1021 width += m_colWidths[ col ];
1022
1023 int height = 0;
1024 for (int row = 0; row < nrows; row++)
1025 height += m_rowHeights[ row ];
1026
1027 return wxSize( width + (ncols-1) * m_hgap,
1028 height + (nrows-1) * m_vgap);
1029 }
1030
1031 void wxFlexGridSizer::AddGrowableRow( size_t idx )
1032 {
1033 m_growableRows.Add( idx );
1034 }
1035
1036 void wxFlexGridSizer::RemoveGrowableRow( size_t WXUNUSED(idx) )
1037 {
1038 }
1039
1040 void wxFlexGridSizer::AddGrowableCol( size_t idx )
1041 {
1042 m_growableCols.Add( idx );
1043 }
1044
1045 void wxFlexGridSizer::RemoveGrowableCol( size_t WXUNUSED(idx) )
1046 {
1047 }
1048
1049 //---------------------------------------------------------------------------
1050 // wxBoxSizer
1051 //---------------------------------------------------------------------------
1052
1053 wxBoxSizer::wxBoxSizer( int orient )
1054 {
1055 m_orient = orient;
1056 }
1057
1058 void wxBoxSizer::RecalcSizes()
1059 {
1060 if (m_children.GetCount() == 0)
1061 return;
1062
1063 int delta = 0;
1064 int extra = 0;
1065 if (m_stretchable)
1066 {
1067 if (m_orient == wxHORIZONTAL)
1068 {
1069 delta = (m_size.x - m_fixedWidth) / m_stretchable;
1070 extra = (m_size.x - m_fixedWidth) % m_stretchable;
1071 }
1072 else
1073 {
1074 delta = (m_size.y - m_fixedHeight) / m_stretchable;
1075 extra = (m_size.y - m_fixedHeight) % m_stretchable;
1076 }
1077 }
1078
1079 wxPoint pt( m_position );
1080
1081 wxNode *node = m_children.GetFirst();
1082 while (node)
1083 {
1084 wxSizerItem *item = (wxSizerItem*) node->Data();
1085 if (item->IsShown())
1086 {
1087 int weight = 1;
1088 if (item->GetOption())
1089 weight = item->GetOption();
1090
1091 wxSize size( item->CalcMin() );
1092
1093 if (m_orient == wxVERTICAL)
1094 {
1095 wxCoord height = size.y;
1096 if (item->GetOption())
1097 {
1098 height = (delta * weight) + extra;
1099 extra = 0; // only the first item will get the remainder as extra size
1100 }
1101
1102 wxPoint child_pos( pt );
1103 wxSize child_size( wxSize( size.x, height) );
1104
1105 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1106 child_size.x = m_size.x;
1107 else if (item->GetFlag() & wxALIGN_RIGHT)
1108 child_pos.x += m_size.x - size.x;
1109 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
1110 // XXX wxCENTER is added for backward compatibility;
1111 // wxALIGN_CENTER should be used in new code
1112 child_pos.x += (m_size.x - size.x) / 2;
1113
1114 item->SetDimension( child_pos, child_size );
1115
1116 pt.y += height;
1117 }
1118 else
1119 {
1120 wxCoord width = size.x;
1121 if (item->GetOption())
1122 {
1123 width = (delta * weight) + extra;
1124 extra = 0; // only the first item will get the remainder as extra size
1125 }
1126
1127 wxPoint child_pos( pt );
1128 wxSize child_size( wxSize(width, size.y) );
1129
1130 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
1131 child_size.y = m_size.y;
1132 else if (item->GetFlag() & wxALIGN_BOTTOM)
1133 child_pos.y += m_size.y - size.y;
1134 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
1135 // XXX wxCENTER is added for backward compatibility;
1136 // wxALIGN_CENTER should be used in new code
1137 child_pos.y += (m_size.y - size.y) / 2;
1138
1139 item->SetDimension( child_pos, child_size );
1140
1141 pt.x += width;
1142 }
1143 }
1144
1145 node = node->Next();
1146 }
1147 }
1148
1149 wxSize wxBoxSizer::CalcMin()
1150 {
1151 if (m_children.GetCount() == 0)
1152 return wxSize(10,10);
1153
1154 m_stretchable = 0;
1155 m_minWidth = 0;
1156 m_minHeight = 0;
1157 m_fixedWidth = 0;
1158 m_fixedHeight = 0;
1159
1160 // Find how long each stretch unit needs to be
1161 int stretchSize = 1;
1162 wxNode *node = m_children.GetFirst();
1163 while (node)
1164 {
1165 wxSizerItem *item = (wxSizerItem*) node->Data();
1166 if (item->IsShown() && item->GetOption() != 0)
1167 {
1168 int stretch = item->GetOption();
1169 wxSize size( item->CalcMin() );
1170 int sizePerStretch;
1171 // Integer division rounded up is (a + b - 1) / b
1172 if (m_orient == wxHORIZONTAL)
1173 sizePerStretch = ( size.x + stretch - 1 ) / stretch;
1174 else
1175 sizePerStretch = ( size.y + stretch - 1 ) / stretch;
1176 if (sizePerStretch > stretchSize)
1177 stretchSize = sizePerStretch;
1178 }
1179 node = node->Next();
1180 }
1181 // Calculate overall minimum size
1182 node = m_children.GetFirst();
1183 while (node)
1184 {
1185 wxSizerItem *item = (wxSizerItem*) node->Data();
1186 if (item->IsShown())
1187 {
1188 m_stretchable += item->GetOption();
1189
1190 wxSize size( item->CalcMin() );
1191 if (item->GetOption() != 0)
1192 {
1193 if (m_orient == wxHORIZONTAL)
1194 size.x = stretchSize * item->GetOption();
1195 else
1196 size.y = stretchSize * item->GetOption();
1197 }
1198
1199 if (m_orient == wxHORIZONTAL)
1200 {
1201 m_minWidth += size.x;
1202 m_minHeight = wxMax( m_minHeight, size.y );
1203 }
1204 else
1205 {
1206 m_minHeight += size.y;
1207 m_minWidth = wxMax( m_minWidth, size.x );
1208 }
1209
1210 if (item->GetOption() == 0)
1211 {
1212 if (m_orient == wxVERTICAL)
1213 {
1214 m_fixedHeight += size.y;
1215 m_fixedWidth = wxMax( m_fixedWidth, size.x );
1216 }
1217 else
1218 {
1219 m_fixedWidth += size.x;
1220 m_fixedHeight = wxMax( m_fixedHeight, size.y );
1221 }
1222 }
1223 }
1224 node = node->Next();
1225 }
1226
1227 return wxSize( m_minWidth, m_minHeight );
1228 }
1229
1230 //---------------------------------------------------------------------------
1231 // wxStaticBoxSizer
1232 //---------------------------------------------------------------------------
1233
1234 #if wxUSE_STATBOX
1235
1236 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
1237 : wxBoxSizer( orient )
1238 {
1239 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
1240
1241 m_staticBox = box;
1242 }
1243
1244 static void GetStaticBoxBorders(wxStaticBox *box,
1245 int *borderTop, int *borderOther)
1246 {
1247 // this has to be done platform by platform as there is no way to
1248 // guess the thickness of a wxStaticBox border
1249 #ifdef __WXGTK__
1250 if ( box->GetLabel().IsEmpty() )
1251 *borderTop = 5;
1252 else
1253 #endif // __WXGTK__
1254 *borderTop = 15;
1255 (void)box;
1256 *borderOther = 5;
1257 }
1258
1259 void wxStaticBoxSizer::RecalcSizes()
1260 {
1261 int top_border, other_border;
1262 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1263
1264 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1265
1266 wxPoint old_pos( m_position );
1267 m_position.x += other_border;
1268 m_position.y += top_border;
1269 wxSize old_size( m_size );
1270 m_size.x -= 2*other_border;
1271 m_size.y -= top_border + other_border;
1272
1273 wxBoxSizer::RecalcSizes();
1274
1275 m_position = old_pos;
1276 m_size = old_size;
1277 }
1278
1279 wxSize wxStaticBoxSizer::CalcMin()
1280 {
1281 int top_border, other_border;
1282 GetStaticBoxBorders(m_staticBox, &top_border, &other_border);
1283
1284 wxSize ret( wxBoxSizer::CalcMin() );
1285 ret.x += 2*other_border;
1286 ret.y += other_border + top_border;
1287
1288 return ret;
1289 }
1290
1291 #endif // wxUSE_STATBOX
1292
1293 //---------------------------------------------------------------------------
1294 // wxNotebookSizer
1295 //---------------------------------------------------------------------------
1296
1297 #if wxUSE_NOTEBOOK
1298
1299 wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
1300 {
1301 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
1302
1303 m_notebook = nb;
1304 }
1305
1306 void wxNotebookSizer::RecalcSizes()
1307 {
1308 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
1309 }
1310
1311 wxSize wxNotebookSizer::CalcMin()
1312 {
1313 wxSize sizeBorder = m_notebook->CalcSizeFromPage(wxSize(0, 0));
1314
1315 sizeBorder.x += 5;
1316 sizeBorder.y += 5;
1317
1318 if (m_notebook->GetChildren().GetCount() == 0)
1319 {
1320 return wxSize(sizeBorder.x + 10, sizeBorder.y + 10);
1321 }
1322
1323 int maxX = 0;
1324 int maxY = 0;
1325
1326 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
1327 while (node)
1328 {
1329 wxWindow *item = node->GetData();
1330 wxSizer *itemsizer = item->GetSizer();
1331
1332 if (itemsizer)
1333 {
1334 wxSize subsize( itemsizer->CalcMin() );
1335
1336 if (subsize.x > maxX)
1337 maxX = subsize.x;
1338 if (subsize.y > maxY)
1339 maxY = subsize.y;
1340 }
1341
1342 node = node->GetNext();
1343 }
1344
1345 return wxSize( maxX, maxY ) + sizeBorder;
1346 }
1347
1348 #endif // wxUSE_NOTEBOOK
1349
1350 // vi:sts=4:sw=4:et