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