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