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