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