]> git.saurik.com Git - wxWidgets.git/blob - src/common/sizer.cpp
wxDataObject changes - ok for MSW, still not for GTK/Motif/...
[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
27 //---------------------------------------------------------------------------
28
29 IMPLEMENT_ABSTRACT_CLASS(wxSizerItem, wxObject);
30 IMPLEMENT_ABSTRACT_CLASS(wxSizer, wxObject);
31 IMPLEMENT_ABSTRACT_CLASS(wxBoxSizer, wxSizer);
32 IMPLEMENT_ABSTRACT_CLASS(wxStaticBoxSizer, wxBoxSizer);
33
34 //---------------------------------------------------------------------------
35 // wxSizerItem
36 //---------------------------------------------------------------------------
37
38 wxSizerItem::wxSizerItem( int width, int height, int option, int flag, int border, wxObject* userData )
39 {
40 m_window = (wxWindow *) NULL;
41 m_sizer = (wxSizer *) NULL;
42 m_option = option;
43 m_border = border;
44 m_flag = flag;
45 m_userData = userData;
46
47 // minimal size is the initial size
48 m_minSize.x = width;
49 m_minSize.y = height;
50
51 // size is set directly
52 m_size = m_minSize;
53 }
54
55 wxSizerItem::wxSizerItem( wxWindow *window, int option, int flag, int border, wxObject* userData )
56 {
57 m_window = window;
58 m_sizer = (wxSizer *) NULL;
59 m_option = option;
60 m_border = border;
61 m_flag = flag;
62 m_userData = userData;
63
64 // minimal size is the initial size
65 m_minSize = window->GetSize();
66
67 // size is calculated later
68 // m_size = ...
69 }
70
71 wxSizerItem::wxSizerItem( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
72 {
73 m_window = (wxWindow *) NULL;
74 m_sizer = sizer;
75 m_option = option;
76 m_border = border;
77 m_flag = flag;
78 m_userData = userData;
79
80 // minimal size is calculated later
81 // m_minSize = ...
82
83 // size is calculated later
84 // m_size = ...
85 }
86
87 wxSizerItem::~wxSizerItem()
88 {
89 if (m_userData)
90 delete m_userData;
91 if (m_sizer)
92 delete m_sizer;
93 }
94
95
96 wxSize wxSizerItem::GetSize()
97 {
98 wxSize ret;
99 if (IsSizer())
100 ret = m_sizer->GetSize();
101 else
102 if (IsWindow())
103 ret = m_window->GetSize();
104 else ret = m_size;
105
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;
114
115 return ret;
116 }
117
118 wxSize wxSizerItem::CalcMin()
119 {
120 wxSize ret;
121 if (IsSizer())
122 ret = m_sizer->CalcMin();
123 /*
124 The minimum size of a window should be the
125 initial size, as saved in m_minSize, not the
126 current size.
127
128 else
129 if (IsWindow())
130 ret = m_window->GetSize();
131 */
132 else ret = m_minSize;
133
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;
142
143 return ret;
144 }
145
146 void wxSizerItem::SetDimension( wxPoint pos, wxSize size )
147 {
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 }
166
167 if (IsSizer())
168 m_sizer->SetDimension( pos.x, pos.y, size.x, size.y );
169
170 if (IsWindow())
171 m_window->SetSize( pos.x, pos.y, size.x, size.y );
172
173 m_size = size;
174 }
175
176 bool wxSizerItem::IsWindow()
177 {
178 return (m_window != NULL);
179 }
180
181 bool wxSizerItem::IsSizer()
182 {
183 return (m_sizer != NULL);
184 }
185
186 bool wxSizerItem::IsSpacer()
187 {
188 return (m_window == NULL) && (m_sizer == NULL);
189 }
190
191 //---------------------------------------------------------------------------
192 // wxSizer
193 //---------------------------------------------------------------------------
194
195 wxSizer::wxSizer()
196 {
197 m_children.DeleteContents( TRUE );
198 }
199
200 wxSizer::~wxSizer()
201 {
202 }
203
204 void wxSizer::Add( wxWindow *window, int option, int flag, int border, wxObject* userData )
205 {
206 m_children.Append( new wxSizerItem( window, option, flag, border, userData ) );
207 }
208
209 void wxSizer::Add( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
210 {
211 m_children.Append( new wxSizerItem( sizer, option, flag, border, userData ) );
212 }
213
214 void wxSizer::Add( int width, int height, int option, int flag, int border, wxObject* userData )
215 {
216 m_children.Append( new wxSizerItem( width, height, option, flag, border, userData ) );
217 }
218
219 void wxSizer::Prepend( wxWindow *window, int option, int flag, int border, wxObject* userData )
220 {
221 m_children.Insert( new wxSizerItem( window, option, flag, border, userData ) );
222 }
223
224 void wxSizer::Prepend( wxSizer *sizer, int option, int flag, int border, wxObject* userData )
225 {
226 m_children.Insert( new wxSizerItem( sizer, option, flag, border, userData ) );
227 }
228
229 void wxSizer::Prepend( int width, int height, int option, int flag, int border, wxObject* userData )
230 {
231 m_children.Insert( new wxSizerItem( width, height, option, flag, border, userData ) );
232 }
233
234 bool wxSizer::Remove( wxWindow *window )
235 {
236 wxASSERT( window );
237
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 }
249
250 return FALSE;
251 }
252
253 bool wxSizer::Remove( wxSizer *sizer )
254 {
255 wxASSERT( sizer );
256
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 }
268
269 return FALSE;
270 }
271
272 bool wxSizer::Remove( int pos )
273 {
274 wxNode *node = m_children.Nth( pos );
275 if (!node) return FALSE;
276
277 m_children.DeleteNode( node );
278
279 return TRUE;
280 }
281
282 void wxSizer::Fit( wxWindow *window )
283 {
284 window->SetSize( GetMinWindowSize( window ) );
285 }
286
287 void wxSizer::Layout()
288 {
289 CalcMin();
290 RecalcSizes();
291 }
292
293 void wxSizer::SetSizeHints( wxWindow *window )
294 {
295 wxSize size( GetMinWindowSize( window ) );
296 window->SetSizeHints( size.x, size.y );
297 }
298
299 wxSize wxSizer::GetMinWindowSize( wxWindow *window )
300 {
301 wxSize minSize( GetMinSize() );
302 wxSize size( window->GetSize() );
303 wxSize client_size( window->GetClientSize() );
304 return wxSize( minSize.x+size.x-client_size.x,
305 minSize.y+size.y-client_size.y );
306 }
307
308 void wxSizer::SetDimension( int x, int y, int width, int height )
309 {
310 m_position.x = x;
311 m_position.y = y;
312 m_size.x = width;
313 m_size.y = height;
314 CalcMin();
315 RecalcSizes();
316 }
317
318 //---------------------------------------------------------------------------
319 // wxBoxSizer
320 //---------------------------------------------------------------------------
321
322 wxBoxSizer::wxBoxSizer( int orient )
323 {
324 m_orient = orient;
325 }
326
327 void wxBoxSizer::RecalcSizes()
328 {
329 if (m_children.GetCount() == 0)
330 return;
331
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 }
347
348 wxPoint pt( m_position );
349
350 wxNode *node = m_children.GetFirst();
351 while (node)
352 {
353 wxSizerItem *item = (wxSizerItem*) node->Data();
354
355 int weight = 1;
356 if (item->GetOption())
357 weight = item->GetOption();
358
359 wxSize size( item->CalcMin() );
360
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 }
369
370 wxPoint child_pos( pt );
371 wxSize child_size( wxSize( size.x, height) );
372
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;
379
380 item->SetDimension( child_pos, child_size );
381
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 }
392
393 wxPoint child_pos( pt );
394 wxSize child_size( wxSize(width, size.y) );
395
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;
402
403 item->SetDimension( child_pos, child_size );
404
405 pt.x += width;
406 }
407
408 node = node->Next();
409 }
410 }
411
412 wxSize wxBoxSizer::CalcMin()
413 {
414 if (m_children.GetCount() == 0)
415 return wxSize(2,2);
416
417 m_stretchable = 0;
418 m_minWidth = 0;
419 m_minHeight = 0;
420 m_fixedWidth = 0;
421 m_fixedHeight = 0;
422
423 wxNode *node = m_children.GetFirst();
424 while (node)
425 {
426 wxSizerItem *item = (wxSizerItem*) node->Data();
427
428 int weight = 1;
429 if (item->GetOption())
430 weight = item->GetOption();
431
432 wxSize size( item->CalcMin() );
433
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 }
444
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 }
462
463 node = node->Next();
464 }
465
466 return wxSize( m_minWidth, m_minHeight );
467 }
468
469 //---------------------------------------------------------------------------
470 // wxStaticBoxSizer
471 //---------------------------------------------------------------------------
472
473 wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient )
474 : wxBoxSizer( orient )
475 {
476 wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") );
477
478 m_staticBox = box;
479 }
480
481 void 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 );
491
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;
498
499 wxBoxSizer::RecalcSizes();
500
501 m_position = old_pos;
502 m_size = old_size;
503 }
504
505 wxSize 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;
513
514 wxSize ret( wxBoxSizer::CalcMin() );
515 ret.x += 2*top_border;
516 ret.y += other_border + top_border;
517
518 return ret;
519 }