]> git.saurik.com Git - wxWidgets.git/blame - src/common/sizer.cpp
Added ComputeHistogram
[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
RR
208 if (IsWindow())
209 m_window->SetSize( pos.x, pos.y, size.x, size.y );
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 ) );
42b4e99e
RR
270}
271
272bool wxSizer::Remove( wxWindow *window )
273{
274 wxASSERT( window );
0c0d686f 275
42b4e99e
RR
276 wxNode *node = m_children.First();
277 while (node)
278 {
279 wxSizerItem *item = (wxSizerItem*)node->Data();
280 if (item->GetWindow() == window)
281 {
282 m_children.DeleteNode( node );
283 return TRUE;
284 }
285 node = node->Next();
286 }
0c0d686f 287
42b4e99e
RR
288 return FALSE;
289}
290
291bool wxSizer::Remove( wxSizer *sizer )
292{
293 wxASSERT( sizer );
0c0d686f 294
42b4e99e
RR
295 wxNode *node = m_children.First();
296 while (node)
297 {
298 wxSizerItem *item = (wxSizerItem*)node->Data();
299 if (item->GetSizer() == sizer)
300 {
301 m_children.DeleteNode( node );
302 return TRUE;
303 }
304 node = node->Next();
305 }
0c0d686f 306
42b4e99e
RR
307 return FALSE;
308}
309
310bool wxSizer::Remove( int pos )
311{
312 wxNode *node = m_children.Nth( pos );
313 if (!node) return FALSE;
0c0d686f 314
42b4e99e 315 m_children.DeleteNode( node );
0c0d686f 316
42b4e99e
RR
317 return TRUE;
318}
0c0d686f 319
3417c2cd 320void wxSizer::Fit( wxWindow *window )
5279a24d
RR
321{
322 window->SetSize( GetMinWindowSize( window ) );
323}
324
3417c2cd 325void wxSizer::Layout()
c62ac5b6 326{
42b4e99e 327 CalcMin();
c62ac5b6
RR
328 RecalcSizes();
329}
330
3417c2cd 331void wxSizer::SetSizeHints( wxWindow *window )
5279a24d
RR
332{
333 wxSize size( GetMinWindowSize( window ) );
334 window->SetSizeHints( size.x, size.y );
335}
336
3417c2cd 337wxSize wxSizer::GetMinWindowSize( wxWindow *window )
5279a24d 338{
77671fd2 339 wxSize minSize( GetMinSize() );
5279a24d
RR
340 wxSize size( window->GetSize() );
341 wxSize client_size( window->GetClientSize() );
77671fd2 342 return wxSize( minSize.x+size.x-client_size.x,
0c0d686f 343 minSize.y+size.y-client_size.y );
5279a24d
RR
344}
345
3417c2cd 346void wxSizer::SetDimension( int x, int y, int width, int height )
5279a24d
RR
347{
348 m_position.x = x;
349 m_position.y = y;
350 m_size.x = width;
351 m_size.y = height;
42b4e99e 352 CalcMin();
5279a24d
RR
353 RecalcSizes();
354}
355
c62ac5b6 356//---------------------------------------------------------------------------
92afa2b1 357// wxBoxSizer
61d514bb
RR
358//---------------------------------------------------------------------------
359
92afa2b1 360wxBoxSizer::wxBoxSizer( int orient )
61d514bb
RR
361{
362 m_orient = orient;
363}
364
92afa2b1 365void wxBoxSizer::RecalcSizes()
61d514bb
RR
366{
367 if (m_children.GetCount() == 0)
61d514bb 368 return;
0c0d686f 369
61d514bb
RR
370 int delta = 0;
371 int extra = 0;
372 if (m_stretchable)
373 {
374 if (m_orient == wxHORIZONTAL)
375 {
376 delta = (m_size.x - m_fixedWidth) / m_stretchable;
377 extra = (m_size.x - m_fixedWidth) % m_stretchable;
378 }
379 else
380 {
381 delta = (m_size.y - m_fixedHeight) / m_stretchable;
382 extra = (m_size.y - m_fixedHeight) % m_stretchable;
383 }
384 }
0c0d686f 385
61d514bb 386 wxPoint pt( m_position );
0c0d686f 387
61d514bb
RR
388 wxNode *node = m_children.GetFirst();
389 while (node)
390 {
3417c2cd 391 wxSizerItem *item = (wxSizerItem*) node->Data();
61d514bb
RR
392
393 int weight = 1;
394 if (item->GetOption())
395 weight = item->GetOption();
0c0d686f 396
61d514bb 397 wxSize size( item->CalcMin() );
0c0d686f 398
61d514bb
RR
399 if (m_orient == wxVERTICAL)
400 {
401 long height = size.y;
402 if (item->GetOption())
403 {
404 height = (delta * weight) + extra;
405 extra = 0; // only the first item will get the remainder as extra size
406 }
0c0d686f 407
d597fcb7
RR
408 wxPoint child_pos( pt );
409 wxSize child_size( wxSize( size.x, height) );
0c0d686f 410
be2577e4
RD
411 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
412 child_size.x = m_size.x;
413 else if (item->GetFlag() & wxALIGN_RIGHT)
d597fcb7 414 child_pos.x += m_size.x - size.x;
be2577e4
RD
415 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
416 // XXX wxCENTER is added for backward compatibility;
417 // wxALIGN_CENTER should be used in new code
d597fcb7 418 child_pos.x += (m_size.x - size.x) / 2;
0c0d686f 419
d597fcb7 420 item->SetDimension( child_pos, child_size );
0c0d686f 421
61d514bb
RR
422 pt.y += height;
423 }
424 else
425 {
426 long width = size.x;
427 if (item->GetOption())
428 {
429 width = (delta * weight) + extra;
430 extra = 0; // only the first item will get the remainder as extra size
431 }
0c0d686f 432
d597fcb7
RR
433 wxPoint child_pos( pt );
434 wxSize child_size( wxSize(width, size.y) );
0c0d686f 435
be2577e4
RD
436 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
437 child_size.y = m_size.y;
438 else if (item->GetFlag() & wxALIGN_BOTTOM)
d597fcb7 439 child_pos.y += m_size.y - size.y;
be2577e4
RD
440 else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
441 // XXX wxCENTER is added for backward compatibility;
442 // wxALIGN_CENTER should be used in new code
d597fcb7 443 child_pos.y += (m_size.y - size.y) / 2;
0c0d686f 444
d597fcb7 445 item->SetDimension( child_pos, child_size );
0c0d686f 446
61d514bb
RR
447 pt.x += width;
448 }
449
450 node = node->Next();
451 }
452}
453
92afa2b1 454wxSize wxBoxSizer::CalcMin()
61d514bb
RR
455{
456 if (m_children.GetCount() == 0)
457 return wxSize(2,2);
0c0d686f 458
61d514bb
RR
459 m_stretchable = 0;
460 m_minWidth = 0;
461 m_minHeight = 0;
462 m_fixedWidth = 0;
463 m_fixedHeight = 0;
0c0d686f 464
61d514bb
RR
465 wxNode *node = m_children.GetFirst();
466 while (node)
467 {
3417c2cd 468 wxSizerItem *item = (wxSizerItem*) node->Data();
0c0d686f 469
61d514bb
RR
470 int weight = 1;
471 if (item->GetOption())
472 weight = item->GetOption();
0c0d686f 473
61d514bb 474 wxSize size( item->CalcMin() );
0c0d686f 475
61d514bb
RR
476 if (m_orient == wxHORIZONTAL)
477 {
478 m_minWidth += (size.x * weight);
479 m_minHeight = wxMax( m_minHeight, size.y );
480 }
481 else
482 {
483 m_minHeight += (size.y * weight);
484 m_minWidth = wxMax( m_minWidth, size.x );
485 }
0c0d686f 486
61d514bb
RR
487 if (item->GetOption())
488 {
489 m_stretchable += weight;
490 }
491 else
492 {
493 if (m_orient == wxVERTICAL)
494 {
495 m_fixedHeight += size.y;
496 m_fixedWidth = wxMax( m_fixedWidth, size.x );
497 }
498 else
499 {
500 m_fixedWidth += size.x;
501 m_fixedHeight = wxMax( m_fixedHeight, size.y );
502 }
503 }
0c0d686f 504
61d514bb
RR
505 node = node->Next();
506 }
0c0d686f 507
61d514bb
RR
508 return wxSize( m_minWidth, m_minHeight );
509}
27ea1d8a
RR
510
511//---------------------------------------------------------------------------
512// wxStaticBoxSizer
513//---------------------------------------------------------------------------
514
515wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
516 : wxBoxSizer( orient )
517{
223d09f6 518 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
0c0d686f 519
27ea1d8a
RR
520 m_staticBox = box;
521}
0c0d686f 522
27ea1d8a
RR
523void wxStaticBoxSizer::RecalcSizes()
524{
525 // this will have to be done platform by platform
526 // as there is no way to guess the thickness of
527 // a wxStaticBox border
528 int top_border = 15;
529 if (m_staticBox->GetLabel().IsEmpty()) top_border = 5;
530 int other_border = 5;
531
532 m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
0c0d686f 533
27ea1d8a
RR
534 wxPoint old_pos( m_position );
535 m_position.x += other_border;
536 m_position.y += top_border;
537 wxSize old_size( m_size );
538 m_size.x -= 2*other_border;
539 m_size.y -= top_border + other_border;
0c0d686f 540
27ea1d8a 541 wxBoxSizer::RecalcSizes();
0c0d686f 542
27ea1d8a
RR
543 m_position = old_pos;
544 m_size = old_size;
545}
546
547wxSize wxStaticBoxSizer::CalcMin()
548{
83edc0a5 549 // This will have to be done platform by platform
27ea1d8a 550 // as there is no way to guess the thickness of
83edc0a5
RR
551 // a wxStaticBox border.
552
27ea1d8a
RR
553 int top_border = 15;
554 if (m_staticBox->GetLabel().IsEmpty()) top_border = 5;
555 int other_border = 5;
0c0d686f 556
27ea1d8a
RR
557 wxSize ret( wxBoxSizer::CalcMin() );
558 ret.x += 2*top_border;
559 ret.y += other_border + top_border;
0c0d686f 560
27ea1d8a
RR
561 return ret;
562}
83edc0a5
RR
563
564//---------------------------------------------------------------------------
565// wxNotebookSizer
566//---------------------------------------------------------------------------
567
60be2f47
VS
568#if wxUSE_NOTEBOOK
569
83edc0a5
RR
570wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
571{
572 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
573
574 m_notebook = nb;
575}
576
577void wxNotebookSizer::RecalcSizes()
578{
579 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
580}
581
582wxSize wxNotebookSizer::CalcMin()
583{
584 // This will have to be done platform by platform
585 // as there is no way to guess the thickness of
586 // the wxNotebook tabs and border.
587
588 int borderX = 5;
589 int borderY = 5;
590 if ((m_notebook->HasFlag(wxNB_RIGHT)) ||
591 (m_notebook->HasFlag(wxNB_LEFT)))
592 {
593 borderX += 70; // improvements later..
594 }
595 else
596 {
597 borderY += 35; // improvements later..
598 }
599
600 if (m_notebook->GetChildren().GetCount() == 0)
601 return wxSize(borderX + 10, borderY + 10);
602
603 int maxX = 0;
604 int maxY = 0;
605
606 wxWindowList::Node *node = m_notebook->GetChildren().GetFirst();
607 while (node)
608 {
609 wxWindow *item = node->GetData();
610 wxSizer *itemsizer = item->GetSizer();
611
612 if (itemsizer)
613 {
614 wxSize subsize( itemsizer->CalcMin() );
615
616 if (subsize.x > maxX) maxX = subsize.x;
617 if (subsize.y > maxY) maxY = subsize.y;
618 }
619
620 node = node->GetNext();
621 }
622
623 return wxSize( borderX + maxX, borderY + maxY );
624}
625
60be2f47 626#endif // wxUSE_NOTEBOOK