]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
wxLogTrace doesn't give messages with two 'Trace' in the beginning
[wxWidgets.git] / src / common / sizer.cpp
CommitLineData
5279a24d
RR
1/////////////////////////////////////////////////////////////////////////////
2// Name: sizer.cpp
1044a386 3// Purpose: provide new wxSizer class for layout
5279a24d
RR
4// Author: Robert Roebling and Robin Dunn
5// Modified by:
0c0d686f 6// Created:
5279a24d
RR
7// RCS-ID: $Id$
8// Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
5279a24d 12#ifdef __GNUG__
c62ac5b6 13#pragma implementation "sizer.h"
5279a24d
RR
14#endif
15
77671fd2
VZ
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifdef __BORLANDC__
20 #pragma hdrstop
21#endif
22
5279a24d 23#include "wx/sizer.h"
61d514bb 24#include "wx/utils.h"
27ea1d8a 25#include "wx/statbox.h"
83edc0a5 26#include "wx/notebook.h"
5279a24d 27
0c0d686f
RD
28//---------------------------------------------------------------------------
29
30IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject);
31IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject);
32IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer);
33IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer);
60be2f47 34#if wxUSE_NOTEBOOK
83edc0a5 35IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer);
60be2f47 36#endif
0c0d686f 37
5279a24d 38//---------------------------------------------------------------------------
3417c2cd 39// wxSizerItem
5279a24d
RR
40//---------------------------------------------------------------------------
41
0c0d686f 42wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
5279a24d
RR
43{
44 m_window = (wxWindow *) NULL;
3417c2cd 45 m_sizer = (wxSizer *) NULL;
d597fcb7
RR
46 m_option = option;
47 m_border = border;
48 m_flag = flag;
0c0d686f
RD
49 m_userData = userData;
50
d597fcb7 51 // minimal size is the initial size
5279a24d 52 m_minSize.x = width;
c62ac5b6 53 m_minSize.y = height;
0c0d686f 54
be2577e4
RD
55 SetRatio(width, height);
56
d597fcb7
RR
57 // size is set directly
58 m_size = m_minSize;
5279a24d
RR
59}
60
0c0d686f 61wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
5279a24d
RR
62{
63 m_window = window;
3417c2cd 64 m_sizer = (wxSizer *) NULL;
5279a24d 65 m_option = option;
d597fcb7
RR
66 m_border = border;
67 m_flag = flag;
0c0d686f
RD
68 m_userData = userData;
69
d597fcb7
RR
70 // minimal size is the initial size
71 m_minSize = window->GetSize();
0c0d686f 72
be2577e4
RD
73 // aspect ratio calculated from initial size
74 SetRatio(m_minSize);
75
d597fcb7
RR
76 // size is calculated later
77 // m_size = ...
5279a24d
RR
78}
79
0c0d686f 80wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
5279a24d
RR
81{
82 m_window = (wxWindow *) NULL;
83 m_sizer = sizer;
5279a24d 84 m_option = option;
d597fcb7
RR
85 m_border = border;
86 m_flag = flag;
0c0d686f
RD
87 m_userData = userData;
88
d597fcb7
RR
89 // minimal size is calculated later
90 // m_minSize = ...
be2577e4 91 m_ratio = 0;
0c0d686f 92
d597fcb7
RR
93 // size is calculated later
94 // m_size = ...
5279a24d
RR
95}
96
0c0d686f
RD
97wxSizerItem::~wxSizerItem()
98{
99 if (m_userData)
100 delete m_userData;
101 if (m_sizer)
102 delete m_sizer;
103}
104
105
3417c2cd 106wxSize wxSizerItem::GetSize()
5279a24d 107{
d597fcb7 108 wxSize ret;
3417c2cd 109 if (IsSizer())
d597fcb7
RR
110 ret = m_sizer->GetSize();
111 else
c62ac5b6 112 if (IsWindow())
d597fcb7
RR
113 ret = m_window->GetSize();
114 else ret = m_size;
0c0d686f 115
d597fcb7
RR
116 if (m_flag & wxWEST)
117 ret.x += m_border;
118 if (m_flag & wxEAST)
119 ret.x += m_border;
120 if (m_flag & wxNORTH)
121 ret.y += m_border;
122 if (m_flag & wxSOUTH)
123 ret.y += m_border;
0c0d686f 124
d597fcb7 125 return ret;
5279a24d
RR
126}
127
3417c2cd 128wxSize wxSizerItem::CalcMin()
c62ac5b6 129{
d597fcb7 130 wxSize ret;
3417c2cd 131 if (IsSizer())
be2577e4 132 {
d597fcb7 133 ret = m_sizer->CalcMin();
be2577e4
RD
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) SetRatio(ret);
137 }
138
0c0d686f 139/*
d597fcb7
RR
140 The minimum size of a window should be the
141 initial size, as saved in m_minSize, not the
142 current size.
0c0d686f 143
d597fcb7 144 else
c62ac5b6 145 if (IsWindow())
d597fcb7
RR
146 ret = m_window->GetSize();
147*/
148 else ret = m_minSize;
0c0d686f 149
d597fcb7
RR
150 if (m_flag & wxWEST)
151 ret.x += m_border;
152 if (m_flag & wxEAST)
153 ret.x += m_border;
154 if (m_flag & wxNORTH)
155 ret.y += m_border;
156 if (m_flag & wxSOUTH)
157 ret.y += m_border;
0c0d686f 158
d597fcb7 159 return ret;
c62ac5b6
RR
160}
161
3417c2cd 162void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
c62ac5b6 163{
d597fcb7
RR
164 if (m_flag & wxWEST)
165 {
166 pos.x += m_border;
167 size.x -= m_border;
168 }
169 if (m_flag & wxEAST)
170 {
171 size.x -= m_border;
172 }
173 if (m_flag & wxNORTH)
174 {
175 pos.y += m_border;
176 size.y -= m_border;
177 }
178 if (m_flag & wxSOUTH)
179 {
180 size.y -= m_border;
181 }
be2577e4
RD
182 if (m_flag & wxSHAPED) {
183 // adjust aspect ratio
184 int rwidth = (int) (size.y * m_ratio);
185 if (rwidth > size.x) {
186 // fit horizontally
187 int rheight = (int) (size.x / m_ratio);
188 // add vertical space
189 if (m_flag & wxALIGN_CENTER_VERTICAL)
190 pos.y += (size.y - rheight) / 2;
191 else if (m_flag & wxALIGN_BOTTOM)
192 pos.y += (size.y - rheight);
193 // use reduced dimensions
194 size.y =rheight;
195 } else if (rwidth < size.x) {
196 // add horizontal space
197 if (m_flag & wxALIGN_CENTER_HORIZONTAL)
198 pos.x += (size.x - rwidth) / 2;
199 else if (m_flag & wxALIGN_RIGHT)
200 pos.x += (size.x - rwidth);
201 size.x = rwidth;
202 }
203 }
0c0d686f 204
3417c2cd 205 if (IsSizer())
c62ac5b6 206 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
0c0d686f 207
c62ac5b6 208 if (IsWindow())
b919f007 209 m_window->SetSize( pos.x, pos.y, size.x, size.y, wxSIZE_ALLOW_MINUS_ONE );
d597fcb7
RR
210
211 m_size = size;
c62ac5b6
RR
212}
213
3417c2cd 214bool wxSizerItem::IsWindow()
5279a24d
RR
215{
216 return (m_window != NULL);
217}
218
3417c2cd 219bool wxSizerItem::IsSizer()
5279a24d
RR
220{
221 return (m_sizer != NULL);
222}
223
3417c2cd 224bool wxSizerItem::IsSpacer()
5279a24d
RR
225{
226 return (m_window == NULL) && (m_sizer == NULL);
227}
228
229//---------------------------------------------------------------------------
3417c2cd 230// wxSizer
5279a24d
RR
231//---------------------------------------------------------------------------
232
3417c2cd 233wxSizer::wxSizer()
5279a24d
RR
234{
235 m_children.DeleteContents( TRUE );
236}
237
3417c2cd 238wxSizer::~wxSizer()
5279a24d
RR
239{
240}
0c0d686f
RD
241
242void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
5279a24d 243{
0c0d686f 244 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
5279a24d
RR
245}
246
0c0d686f 247void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
5279a24d 248{
0c0d686f 249 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
5279a24d
RR
250}
251
0c0d686f 252void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
5279a24d 253{
0c0d686f 254 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
5279a24d
RR
255}
256
0c0d686f 257void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
42b4e99e 258{
0c0d686f 259 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
42b4e99e
RR
260}
261
0c0d686f 262void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
42b4e99e 263{
0c0d686f 264 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
42b4e99e
RR
265}
266
0c0d686f 267void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
42b4e99e 268{
0c0d686f 269 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
f35aa3da
RR
270}
271
272void wxSizer::Insert( int before, wxWindow *window, int option, int flag, int border, wxObject* userData )
273{
274 m_children.Insert( before, new wxSizerItem( window, option, flag, border, userData ) );
275}
276
277void wxSizer::Insert( int before, wxSizer *sizer, int option, int flag, int border, wxObject* userData )
278{
279 m_children.Insert( before, new wxSizerItem( sizer, option, flag, border, userData ) );
280}
281
282void wxSizer::Insert( int before, int width, int height, int option, int flag, int border, wxObject* userData )
283{
284 m_children.Insert( before, new wxSizerItem( width, height, option, flag, border, userData ) );
42b4e99e
RR
285}
286
287bool wxSizer::Remove( wxWindow *window )
288{
289 wxASSERT( window );
0c0d686f 290
42b4e99e
RR
291 wxNode *node = m_children.First();
292 while (node)
293 {
294 wxSizerItem *item = (wxSizerItem*)node->Data();
b919f007
RR
295 if (item->GetWindow() == window)
296 {
42b4e99e 297 m_children.DeleteNode( node );
b919f007
RR
298 return TRUE;
299 }
42b4e99e
RR
300 node = node->Next();
301 }
0c0d686f 302
42b4e99e
RR
303 return FALSE;
304}
305
306bool wxSizer::Remove( wxSizer *sizer )
307{
308 wxASSERT( sizer );
0c0d686f 309
42b4e99e
RR
310 wxNode *node = m_children.First();
311 while (node)
312 {
313 wxSizerItem *item = (wxSizerItem*)node->Data();
b919f007
RR
314 if (item->GetSizer() == sizer)
315 {
42b4e99e 316 m_children.DeleteNode( node );
b919f007
RR
317 return TRUE;
318 }
42b4e99e
RR
319 node = node->Next();
320 }
0c0d686f 321
42b4e99e
RR
322 return FALSE;
323}
324
325bool wxSizer::Remove( int pos )
326{
327 wxNode *node = m_children.Nth( pos );
328 if (!node) return FALSE;
0c0d686f 329
42b4e99e 330 m_children.DeleteNode( node );
0c0d686f 331
42b4e99e
RR
332 return TRUE;
333}
0c0d686f 334
3417c2cd 335void wxSizer::Fit( wxWindow *window )
5279a24d
RR
336{
337 window->SetSize( GetMinWindowSize( window ) );
338}
339
3417c2cd 340void wxSizer::Layout()
c62ac5b6 341{
42b4e99e 342 CalcMin();
c62ac5b6
RR
343 RecalcSizes();
344}
345
3417c2cd 346void wxSizer::SetSizeHints( wxWindow *window )
5279a24d
RR
347{
348 wxSize size( GetMinWindowSize( window ) );
349 window->SetSizeHints( size.x, size.y );
350}
351
3417c2cd 352wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 353{
77671fd2 354 wxSize minSize( GetMinSize() );
5279a24d
RR
355 wxSize size( window->GetSize() );
356 wxSize client_size( window->GetClientSize() );
77671fd2 357 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 358 minSize.y+size.y-client_size.y );
5279a24d
RR
359}
360
3417c2cd 361void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
362{
363 m_position.x = x;
364 m_position.y = y;
365 m_size.x = width;
366 m_size.y = height;
42b4e99e 367 CalcMin();
5279a24d
RR
368 RecalcSizes();
369}
370
c62ac5b6 371//---------------------------------------------------------------------------
92afa2b1 372// wxBoxSizer
61d514bb
RR
373//---------------------------------------------------------------------------
374
92afa2b1 375wxBoxSizer::wxBoxSizer( int orient )
61d514bb
RR
376{
377 m_orient = orient;
378}
379
92afa2b1 380void wxBoxSizer::RecalcSizes()
61d514bb
RR
381{
382 if (m_children.GetCount() == 0)
61d514bb 383 return;
0c0d686f 384
61d514bb
RR
385 int delta = 0;
386 int extra = 0;
387 if (m_stretchable)
388 {
389 if (m_orient == wxHORIZONTAL)
390 {
391 delta = (m_size.x - m_fixedWidth) / m_stretchable;
392 extra = (m_size.x - m_fixedWidth) % m_stretchable;
b919f007
RR
393 }
394 else
395 {
61d514bb
RR
396 delta = (m_size.y - m_fixedHeight) / m_stretchable;
397 extra = (m_size.y - m_fixedHeight) % m_stretchable;
b919f007 398 }
61d514bb 399 }
0c0d686f 400
61d514bb 401 wxPoint pt( m_position );
0c0d686f 402
61d514bb
RR
403 wxNode *node = m_children.GetFirst();
404 while (node)
405 {
3417c2cd 406 wxSizerItem *item = (wxSizerItem*) node->Data();
61d514bb 407
b919f007
RR
408 int weight = 1;
409 if (item->GetOption())
410 weight = item->GetOption();
0c0d686f 411
b919f007 412 wxSize size( item->CalcMin() );
0c0d686f 413
b919f007 414 if (m_orient == wxVERTICAL)
61d514bb 415 {
b919f007
RR
416 wxCoord height = size.y;
417 if (item->GetOption())
418 {
419 height = (delta * weight) + extra;
420 extra = 0; // only the first item will get the remainder as extra size
421 }
422
423 wxPoint child_pos( pt );
424 wxSize child_size( wxSize( size.x, height) );
425
426 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
427 child_size.x = m_size.x;
428 else if (item->GetFlag() & wxALIGN_RIGHT)
429 child_pos.x += m_size.x - size.x;
430 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
431 // XXX wxCENTER is added for backward compatibility;
432 // wxALIGN_CENTER should be used in new code
433 child_pos.x += (m_size.x - size.x) / 2;
434
435 item->SetDimension( child_pos, child_size );
436
437 pt.y += height;
61d514bb 438 }
b919f007 439 else
61d514bb 440 {
b919f007
RR
441 wxCoord width = size.x;
442 if (item->GetOption())
443 {
444 width = (delta * weight) + extra;
445 extra = 0; // only the first item will get the remainder as extra size
446 }
447
448 wxPoint child_pos( pt );
449 wxSize child_size( wxSize(width, size.y) );
450
451 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
452 child_size.y = m_size.y;
453 else if (item->GetFlag() & wxALIGN_BOTTOM)
454 child_pos.y += m_size.y - size.y;
455 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
456 // XXX wxCENTER is added for backward compatibility;
457 // wxALIGN_CENTER should be used in new code
458 child_pos.y += (m_size.y - size.y) / 2;
459
460 item->SetDimension( child_pos, child_size );
461
462 pt.x += width;
61d514bb 463 }
0c0d686f 464
b919f007 465 node = node->Next();
61d514bb
RR
466 }
467}
468
92afa2b1 469wxSize wxBoxSizer::CalcMin()
61d514bb
RR
470{
471 if (m_children.GetCount() == 0)
c7a9fa36 472 return wxSize(10,10);
0c0d686f 473
61d514bb
RR
474 m_stretchable = 0;
475 m_minWidth = 0;
476 m_minHeight = 0;
477 m_fixedWidth = 0;
478 m_fixedHeight = 0;
0c0d686f 479
61d514bb
RR
480 wxNode *node = m_children.GetFirst();
481 while (node)
482 {
3417c2cd 483 wxSizerItem *item = (wxSizerItem*) node->Data();
0c0d686f 484
b919f007
RR
485 int weight = 1;
486 if (item->GetOption())
487 weight = item->GetOption();
488
489 wxSize size( item->CalcMin() );
490
491 if (m_orient == wxHORIZONTAL)
61d514bb 492 {
b919f007
RR
493 m_minWidth += (size.x * weight);
494 m_minHeight = wxMax( m_minHeight, size.y );
61d514bb
RR
495 }
496 else
497 {
b919f007
RR
498 m_minHeight += (size.y * weight);
499 m_minWidth = wxMax( m_minWidth, size.x );
61d514bb 500 }
0c0d686f 501
b919f007
RR
502 if (item->GetOption())
503 {
504 m_stretchable += weight;
505 }
506 else
507 {
508 if (m_orient == wxVERTICAL)
509 {
510 m_fixedHeight += size.y;
511 m_fixedWidth = wxMax( m_fixedWidth, size.x );
512 }
513 else
514 {
515 m_fixedWidth += size.x;
516 m_fixedHeight = wxMax( m_fixedHeight, size.y );
517 }
518 }
519
520 node = node->Next();
61d514bb 521 }
0c0d686f 522
61d514bb
RR
523 return wxSize( m_minWidth, m_minHeight );
524}
27ea1d8a
RR
525
526//---------------------------------------------------------------------------
527// wxStaticBoxSizer
528//---------------------------------------------------------------------------
529
530wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
531 : wxBoxSizer( orient )
532{
223d09f6 533 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
0c0d686f 534
27ea1d8a
RR
535 m_staticBox = box;
536}
0c0d686f 537
27ea1d8a
RR
538void wxStaticBoxSizer::RecalcSizes()
539{
540 // this will have to be done platform by platform
541 // as there is no way to guess the thickness of
542 // a wxStaticBox border
543 int top_border = 15;
544 if (m_staticBox->GetLabel().IsEmpty()) top_border = 5;
545 int other_border = 5;
546
547 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 548
27ea1d8a
RR
549 wxPoint old_pos( m_position );
550 m_position.x += other_border;
551 m_position.y += top_border;
552 wxSize old_size( m_size );
553 m_size.x -= 2*other_border;
554 m_size.y -= top_border + other_border;
0c0d686f 555
27ea1d8a 556 wxBoxSizer::RecalcSizes();
0c0d686f 557
27ea1d8a
RR
558 m_position = old_pos;
559 m_size = old_size;
560}
561
562wxSize wxStaticBoxSizer::CalcMin()
563{
83edc0a5 564 // This will have to be done platform by platform
27ea1d8a 565 // as there is no way to guess the thickness of
83edc0a5
RR
566 // a wxStaticBox border.
567
27ea1d8a
RR
568 int top_border = 15;
569 if (m_staticBox->GetLabel().IsEmpty()) top_border = 5;
570 int other_border = 5;
0c0d686f 571
27ea1d8a 572 wxSize ret( wxBoxSizer::CalcMin() );
cae31b8b 573 ret.x += 2*other_border;
27ea1d8a 574 ret.y += other_border + top_border;
0c0d686f 575
27ea1d8a
RR
576 return ret;
577}
83edc0a5
RR
578
579//---------------------------------------------------------------------------
580// wxNotebookSizer
581//---------------------------------------------------------------------------
582
60be2f47
VS
583#if wxUSE_NOTEBOOK
584
83edc0a5
RR
585wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
586{
587 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
588
589 m_notebook = nb;
590}
591
592void wxNotebookSizer::RecalcSizes()
593{
594 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
595}
596
597wxSize wxNotebookSizer::CalcMin()
598{
599 // This will have to be done platform by platform
600 // as there is no way to guess the thickness of
601 // the wxNotebook tabs and border.
602
603 int borderX = 5;
604 int borderY = 5;
605 if ((m_notebook->HasFlag(wxNB_RIGHT)) ||
606 (m_notebook->HasFlag(wxNB_LEFT)))
607 {
608 borderX += 70; // improvements later..
609 }
610 else
611 {
612 borderY += 35; // improvements later..
613 }
614
615 if (m_notebook->GetChildren().GetCount() == 0)
616 return wxSize(borderX + 10, borderY + 10);
617
618 int maxX = 0;
619 int maxY = 0;
620
621 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
622 while (node)
623 {
624 wxWindow *item = node->GetData();
b919f007 625 wxSizer *itemsizer = item->GetSizer();
83edc0a5 626
b919f007
RR
627 if (itemsizer)
628 {
83edc0a5
RR
629 wxSize subsize( itemsizer->CalcMin() );
630
b919f007
RR
631 if (subsize.x > maxX) maxX = subsize.x;
632 if (subsize.y > maxY) maxY = subsize.y;
633 }
83edc0a5 634
b919f007 635 node = node->GetNext();
83edc0a5
RR
636 }
637
638 return wxSize( borderX + maxX, borderY + maxY );
639}
640
60be2f47 641#endif // wxUSE_NOTEBOOK