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