added wxRESERVE_SPACE_EVEN_IF_HIDDEN support to XRC
[wxWidgets.git] / src / xrc / xh_sizer.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/xrc/xh_sizer.cpp
3 // Purpose: XRC resource for wxBoxSizer
4 // Author: Vaclav Slavik
5 // Created: 2000/03/21
6 // RCS-ID: $Id$
7 // Copyright: (c) 2000 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13
14 #ifdef __BORLANDC__
15 #pragma hdrstop
16 #endif
17
18 #if wxUSE_XRC
19
20 #include "wx/xrc/xh_sizer.h"
21
22 #ifndef WX_PRECOMP
23 #include "wx/log.h"
24 #include "wx/panel.h"
25 #include "wx/statbox.h"
26 #include "wx/sizer.h"
27 #include "wx/frame.h"
28 #include "wx/dialog.h"
29 #include "wx/button.h"
30 #include "wx/scrolwin.h"
31 #endif
32
33 #include "wx/gbsizer.h"
34 #include "wx/notebook.h"
35 #include "wx/tokenzr.h"
36
37
38 //-----------------------------------------------------------------------------
39 // wxSizerXmlHandler
40 //-----------------------------------------------------------------------------
41
42 IMPLEMENT_DYNAMIC_CLASS(wxSizerXmlHandler, wxXmlResourceHandler)
43
44 wxSizerXmlHandler::wxSizerXmlHandler()
45 :wxXmlResourceHandler(),
46 m_isInside(false),
47 m_isGBS(false),
48 m_parentSizer(NULL)
49 {
50 XRC_ADD_STYLE(wxHORIZONTAL);
51 XRC_ADD_STYLE(wxVERTICAL);
52
53 // and flags
54 XRC_ADD_STYLE(wxLEFT);
55 XRC_ADD_STYLE(wxRIGHT);
56 XRC_ADD_STYLE(wxTOP);
57 XRC_ADD_STYLE(wxBOTTOM);
58 XRC_ADD_STYLE(wxNORTH);
59 XRC_ADD_STYLE(wxSOUTH);
60 XRC_ADD_STYLE(wxEAST);
61 XRC_ADD_STYLE(wxWEST);
62 XRC_ADD_STYLE(wxALL);
63
64 XRC_ADD_STYLE(wxGROW);
65 XRC_ADD_STYLE(wxEXPAND);
66 XRC_ADD_STYLE(wxSHAPED);
67 XRC_ADD_STYLE(wxSTRETCH_NOT);
68
69 XRC_ADD_STYLE(wxALIGN_CENTER);
70 XRC_ADD_STYLE(wxALIGN_CENTRE);
71 XRC_ADD_STYLE(wxALIGN_LEFT);
72 XRC_ADD_STYLE(wxALIGN_TOP);
73 XRC_ADD_STYLE(wxALIGN_RIGHT);
74 XRC_ADD_STYLE(wxALIGN_BOTTOM);
75 XRC_ADD_STYLE(wxALIGN_CENTER_HORIZONTAL);
76 XRC_ADD_STYLE(wxALIGN_CENTRE_HORIZONTAL);
77 XRC_ADD_STYLE(wxALIGN_CENTER_VERTICAL);
78 XRC_ADD_STYLE(wxALIGN_CENTRE_VERTICAL);
79
80 XRC_ADD_STYLE(wxFIXED_MINSIZE);
81 XRC_ADD_STYLE(wxRESERVE_SPACE_EVEN_IF_HIDDEN);
82 }
83
84
85
86 bool wxSizerXmlHandler::CanHandle(wxXmlNode *node)
87 {
88 return ( (!m_isInside && IsSizerNode(node)) ||
89 (m_isInside && IsOfClass(node, wxT("sizeritem"))) ||
90 (m_isInside && IsOfClass(node, wxT("spacer")))
91 );
92 }
93
94
95 wxObject* wxSizerXmlHandler::DoCreateResource()
96 {
97 if (m_class == wxT("sizeritem"))
98 return Handle_sizeritem();
99
100 else if (m_class == wxT("spacer"))
101 return Handle_spacer();
102
103 else
104 return Handle_sizer();
105 }
106
107
108
109
110 bool wxSizerXmlHandler::IsSizerNode(wxXmlNode *node)
111 {
112 return (IsOfClass(node, wxT("wxBoxSizer"))) ||
113 (IsOfClass(node, wxT("wxStaticBoxSizer"))) ||
114 (IsOfClass(node, wxT("wxGridSizer"))) ||
115 (IsOfClass(node, wxT("wxFlexGridSizer"))) ||
116 (IsOfClass(node, wxT("wxGridBagSizer")));
117 }
118
119
120 wxObject* wxSizerXmlHandler::Handle_sizeritem()
121 {
122 // find the item to be managed by this sizeritem
123 wxXmlNode *n = GetParamNode(wxT("object"));
124 if ( !n )
125 n = GetParamNode(wxT("object_ref"));
126
127 // did we find one?
128 if (n)
129 {
130 // create a sizer item for it
131 wxSizerItem* sitem = MakeSizerItem();
132
133 // now fetch the item to be managed
134 bool old_gbs = m_isGBS;
135 bool old_ins = m_isInside;
136 wxSizer *old_par = m_parentSizer;
137 m_isInside = false;
138 if (!IsSizerNode(n)) m_parentSizer = NULL;
139 wxObject *item = CreateResFromNode(n, m_parent, NULL);
140 m_isInside = old_ins;
141 m_parentSizer = old_par;
142 m_isGBS = old_gbs;
143
144 // and figure out what type it is
145 wxSizer *sizer = wxDynamicCast(item, wxSizer);
146 wxWindow *wnd = wxDynamicCast(item, wxWindow);
147
148 if (sizer)
149 sitem->AssignSizer(sizer);
150 else if (wnd)
151 sitem->AssignWindow(wnd);
152 else
153 wxLogError(wxT("Error in resource."));
154
155 // finally, set other wxSizerItem attributes
156 SetSizerItemAttributes(sitem);
157
158 AddSizerItem(sitem);
159 return item;
160 }
161 else /*n == NULL*/
162 {
163 wxLogError(wxT("Error in resource: no window/sizer/spacer within sizeritem object."));
164 return NULL;
165 }
166 }
167
168
169 wxObject* wxSizerXmlHandler::Handle_spacer()
170 {
171 wxCHECK_MSG(m_parentSizer, NULL, wxT("Incorrect syntax of XRC resource: spacer not within sizer!"));
172
173 wxSizerItem* sitem = MakeSizerItem();
174 SetSizerItemAttributes(sitem);
175 sitem->AssignSpacer(GetSize());
176 AddSizerItem(sitem);
177 return NULL;
178 }
179
180
181 wxObject* wxSizerXmlHandler::Handle_sizer()
182 {
183 wxSizer *sizer = NULL;
184
185 wxXmlNode *parentNode = m_node->GetParent();
186
187 wxCHECK_MSG(m_parentSizer != NULL ||
188 (parentNode && parentNode->GetType() == wxXML_ELEMENT_NODE &&
189 m_parentAsWindow), NULL,
190 wxT("Sizer must have a window parent node"));
191
192 if (m_class == wxT("wxBoxSizer"))
193 sizer = Handle_wxBoxSizer();
194
195 #if wxUSE_STATBOX
196 else if (m_class == wxT("wxStaticBoxSizer"))
197 sizer = Handle_wxStaticBoxSizer();
198 #endif
199
200 else if (m_class == wxT("wxGridSizer"))
201 sizer = Handle_wxGridSizer();
202
203 else if (m_class == wxT("wxFlexGridSizer"))
204 sizer = Handle_wxFlexGridSizer();
205
206 else if (m_class == wxT("wxGridBagSizer"))
207 sizer = Handle_wxGridBagSizer();
208
209 if ( !sizer )
210 {
211 wxLogError(_T("Failed to create size of class \"%s\""), m_class.c_str());
212 return NULL;
213 }
214
215 wxSize minsize = GetSize(wxT("minsize"));
216 if (!(minsize == wxDefaultSize))
217 sizer->SetMinSize(minsize);
218
219 // save state
220 wxSizer *old_par = m_parentSizer;
221 bool old_ins = m_isInside;
222
223 // set new state
224 m_parentSizer = sizer;
225 m_isInside = true;
226 m_isGBS = (m_class == wxT("wxGridBagSizer"));
227
228 CreateChildren(m_parent, true/*only this handler*/);
229
230 // restore state
231 m_isInside = old_ins;
232 m_parentSizer = old_par;
233
234 if (m_parentSizer == NULL) // setup window:
235 {
236 m_parentAsWindow->SetSizer(sizer);
237
238 wxXmlNode *nd = m_node;
239 m_node = parentNode;
240 if (GetSize() == wxDefaultSize)
241 {
242 if ( wxDynamicCast(m_parentAsWindow, wxScrolledWindow) != NULL )
243 {
244 sizer->FitInside(m_parentAsWindow);
245 }
246 else
247 {
248 sizer->Fit(m_parentAsWindow);
249 }
250 }
251 m_node = nd;
252
253 if (m_parentAsWindow->IsTopLevel())
254 {
255 sizer->SetSizeHints(m_parentAsWindow);
256 }
257 }
258
259 return sizer;
260 }
261
262
263 wxSizer* wxSizerXmlHandler::Handle_wxBoxSizer()
264 {
265 return new wxBoxSizer(GetStyle(wxT("orient"), wxHORIZONTAL));
266 }
267
268 #if wxUSE_STATBOX
269 wxSizer* wxSizerXmlHandler::Handle_wxStaticBoxSizer()
270 {
271 return new wxStaticBoxSizer(
272 new wxStaticBox(m_parentAsWindow,
273 GetID(),
274 GetText(wxT("label")),
275 wxDefaultPosition, wxDefaultSize,
276 0/*style*/,
277 GetName()),
278 GetStyle(wxT("orient"), wxHORIZONTAL));
279 }
280 #endif // wxUSE_STATBOX
281
282 wxSizer* wxSizerXmlHandler::Handle_wxGridSizer()
283 {
284 return new wxGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")),
285 GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
286 }
287
288
289 wxSizer* wxSizerXmlHandler::Handle_wxFlexGridSizer()
290 {
291 wxFlexGridSizer *sizer =
292 new wxFlexGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")),
293 GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
294 SetGrowables(sizer, wxT("growablerows"), true);
295 SetGrowables(sizer, wxT("growablecols"), false);
296 return sizer;
297 }
298
299
300 wxSizer* wxSizerXmlHandler::Handle_wxGridBagSizer()
301 {
302 wxGridBagSizer *sizer =
303 new wxGridBagSizer(GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
304 SetGrowables(sizer, wxT("growablerows"), true);
305 SetGrowables(sizer, wxT("growablecols"), false);
306 return sizer;
307 }
308
309
310
311
312 void wxSizerXmlHandler::SetGrowables(wxFlexGridSizer* sizer,
313 const wxChar* param,
314 bool rows)
315 {
316 wxStringTokenizer tkn;
317 unsigned long l;
318 tkn.SetString(GetParamValue(param), wxT(","));
319 while (tkn.HasMoreTokens())
320 {
321 if (!tkn.GetNextToken().ToULong(&l))
322 wxLogError(wxT("growable[rows|cols] must be comma-separated list of row numbers"));
323 else {
324 if (rows)
325 sizer->AddGrowableRow(l);
326 else
327 sizer->AddGrowableCol(l);
328 }
329 }
330 }
331
332
333 wxGBPosition wxSizerXmlHandler::GetGBPos(const wxString& param)
334 {
335 wxSize sz = GetSize(param);
336 if (sz.x < 0) sz.x = 0;
337 if (sz.y < 0) sz.y = 0;
338 return wxGBPosition(sz.x, sz.y);
339 }
340
341 wxGBSpan wxSizerXmlHandler::GetGBSpan(const wxString& param)
342 {
343 wxSize sz = GetSize(param);
344 if (sz.x < 1) sz.x = 1;
345 if (sz.y < 1) sz.y = 1;
346 return wxGBSpan(sz.x, sz.y);
347 }
348
349
350
351 wxSizerItem* wxSizerXmlHandler::MakeSizerItem()
352 {
353 if (m_isGBS)
354 return new wxGBSizerItem();
355 else
356 return new wxSizerItem();
357 }
358
359 void wxSizerXmlHandler::SetSizerItemAttributes(wxSizerItem* sitem)
360 {
361 sitem->SetProportion(GetLong(wxT("option"))); // Should this check for "proportion" too?
362 sitem->SetFlag(GetStyle(wxT("flag")));
363 sitem->SetBorder(GetDimension(wxT("border")));
364 wxSize sz = GetSize(wxT("minsize"));
365 if (!(sz == wxDefaultSize))
366 sitem->SetMinSize(sz);
367 sz = GetSize(wxT("ratio"));
368 if (!(sz == wxDefaultSize))
369 sitem->SetRatio(sz);
370
371 if (m_isGBS)
372 {
373 wxGBSizerItem* gbsitem = (wxGBSizerItem*)sitem;
374 gbsitem->SetPos(GetGBPos(wxT("cellpos")));
375 gbsitem->SetSpan(GetGBSpan(wxT("cellspan")));
376 }
377
378 // record the id of the item, if any, for use by XRCSIZERITEM()
379 sitem->SetId(GetID());
380 }
381
382 void wxSizerXmlHandler::AddSizerItem(wxSizerItem* sitem)
383 {
384 if (m_isGBS)
385 ((wxGridBagSizer*)m_parentSizer)->Add((wxGBSizerItem*)sitem);
386 else
387 m_parentSizer->Add(sitem);
388 }
389
390
391
392 //-----------------------------------------------------------------------------
393 // wxStdDialogButtonSizerXmlHandler
394 //-----------------------------------------------------------------------------
395 #if wxUSE_BUTTON
396
397 IMPLEMENT_DYNAMIC_CLASS(wxStdDialogButtonSizerXmlHandler, wxXmlResourceHandler)
398
399 wxStdDialogButtonSizerXmlHandler::wxStdDialogButtonSizerXmlHandler()
400 : m_isInside(false), m_parentSizer(NULL)
401 {
402 }
403
404 wxObject *wxStdDialogButtonSizerXmlHandler::DoCreateResource()
405 {
406 if (m_class == wxT("wxStdDialogButtonSizer"))
407 {
408 wxASSERT( !m_parentSizer );
409
410 wxSizer *s = m_parentSizer = new wxStdDialogButtonSizer;
411 m_isInside = true;
412
413 CreateChildren(m_parent, true/*only this handler*/);
414
415 m_parentSizer->Realize();
416
417 m_isInside = false;
418 m_parentSizer = NULL;
419
420 return s;
421 }
422 else // m_class == "button"
423 {
424 wxASSERT( m_parentSizer );
425
426 // find the item to be managed by this sizeritem
427 wxXmlNode *n = GetParamNode(wxT("object"));
428 if ( !n )
429 n = GetParamNode(wxT("object_ref"));
430
431 // did we find one?
432 if (n)
433 {
434 wxObject *item = CreateResFromNode(n, m_parent, NULL);
435 wxButton *button = wxDynamicCast(item, wxButton);
436
437 if (button)
438 m_parentSizer->AddButton(button);
439 else
440 wxLogError(wxT("Error in resource - expected button."));
441
442 return item;
443 }
444 else /*n == NULL*/
445 {
446 wxLogError(wxT("Error in resource: no button within wxStdDialogButtonSizer."));
447 return NULL;
448 }
449 }
450 }
451
452 bool wxStdDialogButtonSizerXmlHandler::CanHandle(wxXmlNode *node)
453 {
454 return (!m_isInside && IsOfClass(node, wxT("wxStdDialogButtonSizer"))) ||
455 (m_isInside && IsOfClass(node, wxT("button")));
456 }
457 #endif // wxUSE_BUTTON
458
459 #endif // wxUSE_XRC