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