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