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