]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
added #if wxUSE_NOTEBOOK around wxNotebookSizer
[wxWidgets.git] / src / common / sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: sizer.cpp
3 // Purpose: provide new wxSizer class for layout
4 // Author: Robert Roebling and Robin Dunn
5 // Modified by:
6 // Created:
7 // RCS-ID: $Id$
8 // Copyright: (c) Robin Dunn, Dirk Holtwick and Robert Roebling
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "sizer.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #include "wx/sizer.h"
24 #include "wx/utils.h"
25 #include "wx/statbox.h"
26 #include "wx/notebook.h"
27
28 //---------------------------------------------------------------------------
29
30 IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject);
31 IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject);
32 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer);
33 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer);
34 #if wxUSE_NOTEBOOK
35 IMPLEMENT_ABSTRACT_CLASS(wxNotebookSizer, wxSizer);
36 #endif
37
38 //---------------------------------------------------------------------------
39 // wxSizerItem
40 //---------------------------------------------------------------------------
41
42 wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
43 {
44 m_window = (wxWindow *) NULL;
45 m_sizer = (wxSizer *) NULL;
46 m_option = option;
47 m_border = border;
48 m_flag = flag;
49 m_userData = userData;
50
51 // minimal size is the initial size
52 m_minSize.x = width;
53 m_minSize.y = height;
54
55 SetRatio(width, height);
56
57 // size is set directly
58 m_size = m_minSize;
59 }
60
61 wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
62 {
63 m_window = window;
64 m_sizer = (wxSizer *) NULL;
65 m_option = option;
66 m_border = border;
67 m_flag = flag;
68 m_userData = userData;
69
70 // minimal size is the initial size
71 m_minSize = window->GetSize();
72
73 // aspect ratio calculated from initial size
74 SetRatio(m_minSize);
75
76 // size is calculated later
77 // m_size = ...
78 }
79
80 wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
81 {
82 m_window = (wxWindow *) NULL;
83 m_sizer = sizer;
84 m_option = option;
85 m_border = border;
86 m_flag = flag;
87 m_userData = userData;
88
89 // minimal size is calculated later
90 // m_minSize = ...
91 m_ratio = 0;
92
93 // size is calculated later
94 // m_size = ...
95 }
96
97 wxSizerItem::~wxSizerItem()
98 {
99 if (m_userData)
100 delete m_userData;
101 if (m_sizer)
102 delete m_sizer;
103 }
104
105
106 wxSize wxSizerItem::GetSize()
107 {
108 wxSize ret;
109 if (IsSizer())
110 ret = m_sizer->GetSize();
111 else
112 if (IsWindow())
113 ret = m_window->GetSize();
114 else ret = m_size;
115
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;
124
125 return ret;
126 }
127
128 wxSize wxSizerItem::CalcMin()
129 {
130 wxSize ret;
131 if (IsSizer())
132 {
133 ret = m_sizer->CalcMin();
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
139 /*
140 The minimum size of a window should be the
141 initial size, as saved in m_minSize, not the
142 current size.
143
144 else
145 if (IsWindow())
146 ret = m_window->GetSize();
147 */
148 else ret = m_minSize;
149
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;
158
159 return ret;
160 }
161
162 void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
163 {
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 }
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 }
204
205 if (IsSizer())
206 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
207
208 if (IsWindow())
209 m_window->SetSize( pos.x, pos.y, size.x, size.y );
210
211 m_size = size;
212 }
213
214 bool wxSizerItem::IsWindow()
215 {
216 return (m_window != NULL);
217 }
218
219 bool wxSizerItem::IsSizer()
220 {
221 return (m_sizer != NULL);
222 }
223
224 bool wxSizerItem::IsSpacer()
225 {
226 return (m_window == NULL) && (m_sizer == NULL);
227 }
228
229 //---------------------------------------------------------------------------
230 // wxSizer
231 //---------------------------------------------------------------------------
232
233 wxSizer::wxSizer()
234 {
235 m_children.DeleteContents( TRUE );
236 }
237
238 wxSizer::~wxSizer()
239 {
240 }
241
242 void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
243 {
244 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
245 }
246
247 void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
248 {
249 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
250 }
251
252 void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
253 {
254 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
255 }
256
257 void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
258 {
259 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
260 }
261
262 void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
263 {
264 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
265 }
266
267 void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
268 {
269 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
270 }
271
272 bool wxSizer::Remove( wxWindow *window )
273 {
274 wxASSERT( window );
275
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 }
287
288 return FALSE;
289 }
290
291 bool wxSizer::Remove( wxSizer *sizer )
292 {
293 wxASSERT( sizer );
294
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 }
306
307 return FALSE;
308 }
309
310 bool wxSizer::Remove( int pos )
311 {
312 wxNode *node = m_children.Nth( pos );
313 if (!node) return FALSE;
314
315 m_children.DeleteNode( node );
316
317 return TRUE;
318 }
319
320 void wxSizer::Fit( wxWindow *window )
321 {
322 window->SetSize( GetMinWindowSize( window ) );
323 }
324
325 void wxSizer::Layout()
326 {
327 CalcMin();
328 RecalcSizes();
329 }
330
331 void wxSizer::SetSizeHints( wxWindow *window )
332 {
333 wxSize size( GetMinWindowSize( window ) );
334 window->SetSizeHints( size.x, size.y );
335 }
336
337 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
338 {
339 wxSize minSize( GetMinSize() );
340 wxSize size( window->GetSize() );
341 wxSize client_size( window->GetClientSize() );
342 return wxSize( minSize.x+size.x-client_size.x,
343 minSize.y+size.y-client_size.y );
344 }
345
346 void wxSizer::SetDimension( int x, int y, int width, int height )
347 {
348 m_position.x = x;
349 m_position.y = y;
350 m_size.x = width;
351 m_size.y = height;
352 CalcMin();
353 RecalcSizes();
354 }
355
356 //---------------------------------------------------------------------------
357 // wxBoxSizer
358 //---------------------------------------------------------------------------
359
360 wxBoxSizer::wxBoxSizer( int orient )
361 {
362 m_orient = orient;
363 }
364
365 void wxBoxSizer::RecalcSizes()
366 {
367 if (m_children.GetCount() == 0)
368 return;
369
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 }
385
386 wxPoint pt( m_position );
387
388 wxNode *node = m_children.GetFirst();
389 while (node)
390 {
391 wxSizerItem *item = (wxSizerItem*) node->Data();
392
393 int weight = 1;
394 if (item->GetOption())
395 weight = item->GetOption();
396
397 wxSize size( item->CalcMin() );
398
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 }
407
408 wxPoint child_pos( pt );
409 wxSize child_size( wxSize( size.x, height) );
410
411 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
412 child_size.x = m_size.x;
413 else if (item->GetFlag() & wxALIGN_RIGHT)
414 child_pos.x += m_size.x - size.x;
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
418 child_pos.x += (m_size.x - size.x) / 2;
419
420 item->SetDimension( child_pos, child_size );
421
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 }
432
433 wxPoint child_pos( pt );
434 wxSize child_size( wxSize(width, size.y) );
435
436 if (item->GetFlag() & (wxEXPAND | wxSHAPED))
437 child_size.y = m_size.y;
438 else if (item->GetFlag() & wxALIGN_BOTTOM)
439 child_pos.y += m_size.y - size.y;
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
443 child_pos.y += (m_size.y - size.y) / 2;
444
445 item->SetDimension( child_pos, child_size );
446
447 pt.x += width;
448 }
449
450 node = node->Next();
451 }
452 }
453
454 wxSize wxBoxSizer::CalcMin()
455 {
456 if (m_children.GetCount() == 0)
457 return wxSize(2,2);
458
459 m_stretchable = 0;
460 m_minWidth = 0;
461 m_minHeight = 0;
462 m_fixedWidth = 0;
463 m_fixedHeight = 0;
464
465 wxNode *node = m_children.GetFirst();
466 while (node)
467 {
468 wxSizerItem *item = (wxSizerItem*) node->Data();
469
470 int weight = 1;
471 if (item->GetOption())
472 weight = item->GetOption();
473
474 wxSize size( item->CalcMin() );
475
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 }
486
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 }
504
505 node = node->Next();
506 }
507
508 return wxSize( m_minWidth, m_minHeight );
509 }
510
511 //---------------------------------------------------------------------------
512 // wxStaticBoxSizer
513 //---------------------------------------------------------------------------
514
515 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
516 : wxBoxSizer( orient )
517 {
518 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
519
520 m_staticBox = box;
521 }
522
523 void 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 );
533
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;
540
541 wxBoxSizer::RecalcSizes();
542
543 m_position = old_pos;
544 m_size = old_size;
545 }
546
547 wxSize wxStaticBoxSizer::CalcMin()
548 {
549 // This will have to be done platform by platform
550 // as there is no way to guess the thickness of
551 // a wxStaticBox border.
552
553 int top_border = 15;
554 if (m_staticBox->GetLabel().IsEmpty()) top_border = 5;
555 int other_border = 5;
556
557 wxSize ret( wxBoxSizer::CalcMin() );
558 ret.x += 2*top_border;
559 ret.y += other_border + top_border;
560
561 return ret;
562 }
563
564 //---------------------------------------------------------------------------
565 // wxNotebookSizer
566 //---------------------------------------------------------------------------
567
568 #if wxUSE_NOTEBOOK
569
570 wxNotebookSizer::wxNotebookSizer( wxNotebook *nb )
571 {
572 wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a notebook") );
573
574 m_notebook = nb;
575 }
576
577 void wxNotebookSizer::RecalcSizes()
578 {
579 m_notebook->SetSize( m_position.x, m_position.y, m_size.x, m_size.y );
580 }
581
582 wxSize 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
626 #endif // wxUSE_NOTEBOOK