1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/xrc/xh_sizer.cpp
3 // Purpose: XRC resource for wxBoxSizer
4 // Author: Vaclav Slavik
7 // Copyright: (c) 2000 Vaclav Slavik
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
20 #include "wx/xrc/xh_sizer.h"
25 #include "wx/statbox.h"
28 #include "wx/dialog.h"
29 #include "wx/button.h"
30 #include "wx/scrolwin.h"
33 #include "wx/gbsizer.h"
34 #include "wx/wrapsizer.h"
35 #include "wx/notebook.h"
36 #include "wx/tokenzr.h"
38 #include "wx/xml/xml.h"
40 //-----------------------------------------------------------------------------
42 //-----------------------------------------------------------------------------
44 IMPLEMENT_DYNAMIC_CLASS(wxSizerXmlHandler
, wxXmlResourceHandler
)
46 wxSizerXmlHandler::wxSizerXmlHandler()
47 :wxXmlResourceHandler(),
52 XRC_ADD_STYLE(wxHORIZONTAL
);
53 XRC_ADD_STYLE(wxVERTICAL
);
56 XRC_ADD_STYLE(wxLEFT
);
57 XRC_ADD_STYLE(wxRIGHT
);
59 XRC_ADD_STYLE(wxBOTTOM
);
60 XRC_ADD_STYLE(wxNORTH
);
61 XRC_ADD_STYLE(wxSOUTH
);
62 XRC_ADD_STYLE(wxEAST
);
63 XRC_ADD_STYLE(wxWEST
);
66 XRC_ADD_STYLE(wxGROW
);
67 XRC_ADD_STYLE(wxEXPAND
);
68 XRC_ADD_STYLE(wxSHAPED
);
69 XRC_ADD_STYLE(wxSTRETCH_NOT
);
71 XRC_ADD_STYLE(wxALIGN_CENTER
);
72 XRC_ADD_STYLE(wxALIGN_CENTRE
);
73 XRC_ADD_STYLE(wxALIGN_LEFT
);
74 XRC_ADD_STYLE(wxALIGN_TOP
);
75 XRC_ADD_STYLE(wxALIGN_RIGHT
);
76 XRC_ADD_STYLE(wxALIGN_BOTTOM
);
77 XRC_ADD_STYLE(wxALIGN_CENTER_HORIZONTAL
);
78 XRC_ADD_STYLE(wxALIGN_CENTRE_HORIZONTAL
);
79 XRC_ADD_STYLE(wxALIGN_CENTER_VERTICAL
);
80 XRC_ADD_STYLE(wxALIGN_CENTRE_VERTICAL
);
82 XRC_ADD_STYLE(wxFIXED_MINSIZE
);
83 XRC_ADD_STYLE(wxRESERVE_SPACE_EVEN_IF_HIDDEN
);
85 // this flag doesn't do anything any more but we can just ignore its
86 // occurrences in the old resource files instead of raising a fuss because
88 AddStyle("wxADJUST_MINSIZE", 0);
90 // wxWrapSizer-specific flags
91 XRC_ADD_STYLE(wxEXTEND_LAST_ON_EACH_LINE
);
92 XRC_ADD_STYLE(wxREMOVE_LEADING_SPACES
);
97 bool wxSizerXmlHandler::CanHandle(wxXmlNode
*node
)
99 return ( (!m_isInside
&& IsSizerNode(node
)) ||
100 (m_isInside
&& IsOfClass(node
, wxT("sizeritem"))) ||
101 (m_isInside
&& IsOfClass(node
, wxT("spacer")))
106 wxObject
* wxSizerXmlHandler::DoCreateResource()
108 if (m_class
== wxT("sizeritem"))
109 return Handle_sizeritem();
111 else if (m_class
== wxT("spacer"))
112 return Handle_spacer();
115 return Handle_sizer();
119 wxSizer
* wxSizerXmlHandler::DoCreateSizer(const wxString
& name
)
121 if (name
== wxT("wxBoxSizer"))
122 return Handle_wxBoxSizer();
124 else if (name
== wxT("wxStaticBoxSizer"))
125 return Handle_wxStaticBoxSizer();
127 else if (name
== wxT("wxGridSizer"))
129 if ( !ValidateGridSizerChildren() )
131 return Handle_wxGridSizer();
133 else if (name
== wxT("wxFlexGridSizer"))
135 return Handle_wxFlexGridSizer();
137 else if (name
== wxT("wxGridBagSizer"))
139 return Handle_wxGridBagSizer();
141 else if (name
== wxT("wxWrapSizer"))
143 return Handle_wxWrapSizer();
146 ReportError(wxString::Format("unknown sizer class \"%s\"", name
));
152 bool wxSizerXmlHandler::IsSizerNode(wxXmlNode
*node
) const
154 return (IsOfClass(node
, wxT("wxBoxSizer"))) ||
155 (IsOfClass(node
, wxT("wxStaticBoxSizer"))) ||
156 (IsOfClass(node
, wxT("wxGridSizer"))) ||
157 (IsOfClass(node
, wxT("wxFlexGridSizer"))) ||
158 (IsOfClass(node
, wxT("wxGridBagSizer"))) ||
159 (IsOfClass(node
, wxT("wxWrapSizer")));
163 wxObject
* wxSizerXmlHandler::Handle_sizeritem()
165 // find the item to be managed by this sizeritem
166 wxXmlNode
*n
= GetParamNode(wxT("object"));
168 n
= GetParamNode(wxT("object_ref"));
173 // create a sizer item for it
174 wxSizerItem
* sitem
= MakeSizerItem();
176 // now fetch the item to be managed
177 bool old_gbs
= m_isGBS
;
178 bool old_ins
= m_isInside
;
179 wxSizer
*old_par
= m_parentSizer
;
181 if (!IsSizerNode(n
)) m_parentSizer
= NULL
;
182 wxObject
*item
= CreateResFromNode(n
, m_parent
, NULL
);
183 m_isInside
= old_ins
;
184 m_parentSizer
= old_par
;
187 // and figure out what type it is
188 wxSizer
*sizer
= wxDynamicCast(item
, wxSizer
);
189 wxWindow
*wnd
= wxDynamicCast(item
, wxWindow
);
192 sitem
->AssignSizer(sizer
);
194 sitem
->AssignWindow(wnd
);
196 ReportError(n
, "unexpected item in sizer");
198 // finally, set other wxSizerItem attributes
199 SetSizerItemAttributes(sitem
);
206 ReportError("no window/sizer/spacer within sizeritem object");
212 wxObject
* wxSizerXmlHandler::Handle_spacer()
214 if ( !m_parentSizer
)
216 ReportError("spacer only allowed inside a sizer");
220 wxSizerItem
* sitem
= MakeSizerItem();
221 SetSizerItemAttributes(sitem
);
222 sitem
->AssignSpacer(GetSize());
228 wxObject
* wxSizerXmlHandler::Handle_sizer()
230 wxXmlNode
*parentNode
= m_node
->GetParent();
232 if ( !m_parentSizer
&&
233 (!parentNode
|| parentNode
->GetType() != wxXML_ELEMENT_NODE
||
236 ReportError("sizer must have a window parent");
240 // Create the sizer of the appropriate class.
241 wxSizer
* const sizer
= DoCreateSizer(m_class
);
243 // creation of sizer failed for some (already reported) reason, so exit:
247 wxSize minsize
= GetSize(wxT("minsize"));
248 if (!(minsize
== wxDefaultSize
))
249 sizer
->SetMinSize(minsize
);
252 wxSizer
*old_par
= m_parentSizer
;
253 bool old_ins
= m_isInside
;
256 m_parentSizer
= sizer
;
258 m_isGBS
= (m_class
== wxT("wxGridBagSizer"));
260 wxObject
* parent
= m_parent
;
262 // wxStaticBoxSizer's child controls should be parented by the box itself,
264 wxStaticBoxSizer
* const stsizer
= wxDynamicCast(sizer
, wxStaticBoxSizer
);
266 parent
= stsizer
->GetStaticBox();
267 #endif // wxUSE_STATBOX
269 CreateChildren(parent
, true/*only this handler*/);
271 // set growable rows and cols for sizers which support this
272 if ( wxFlexGridSizer
*flexsizer
= wxDynamicCast(sizer
, wxFlexGridSizer
) )
274 SetFlexibleMode(flexsizer
);
275 SetGrowables(flexsizer
, wxT("growablerows"), true);
276 SetGrowables(flexsizer
, wxT("growablecols"), false);
280 m_isInside
= old_ins
;
281 m_parentSizer
= old_par
;
283 if (m_parentSizer
== NULL
) // setup window:
285 m_parentAsWindow
->SetSizer(sizer
);
287 wxXmlNode
*nd
= m_node
;
289 if (GetSize() == wxDefaultSize
)
291 if ( wxDynamicCast(m_parentAsWindow
, wxScrolledWindow
) != NULL
)
293 sizer
->FitInside(m_parentAsWindow
);
297 sizer
->Fit(m_parentAsWindow
);
302 if (m_parentAsWindow
->IsTopLevel())
304 sizer
->SetSizeHints(m_parentAsWindow
);
312 wxSizer
* wxSizerXmlHandler::Handle_wxBoxSizer()
314 return new wxBoxSizer(GetStyle(wxT("orient"), wxHORIZONTAL
));
318 wxSizer
* wxSizerXmlHandler::Handle_wxStaticBoxSizer()
320 return new wxStaticBoxSizer(
321 new wxStaticBox(m_parentAsWindow
,
323 GetText(wxT("label")),
324 wxDefaultPosition
, wxDefaultSize
,
327 GetStyle(wxT("orient"), wxHORIZONTAL
));
329 #endif // wxUSE_STATBOX
331 wxSizer
* wxSizerXmlHandler::Handle_wxGridSizer()
333 return new wxGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")),
334 GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
338 wxFlexGridSizer
* wxSizerXmlHandler::Handle_wxFlexGridSizer()
340 if ( !ValidateGridSizerChildren() )
342 return new wxFlexGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")),
343 GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
347 wxGridBagSizer
* wxSizerXmlHandler::Handle_wxGridBagSizer()
349 if ( !ValidateGridSizerChildren() )
351 return new wxGridBagSizer(GetDimension(wxT("vgap")), GetDimension(wxT("hgap")));
354 wxSizer
* wxSizerXmlHandler::Handle_wxWrapSizer()
356 wxWrapSizer
*sizer
= new wxWrapSizer(GetStyle("orient"), GetStyle("flag"));
361 bool wxSizerXmlHandler::ValidateGridSizerChildren()
363 int rows
= GetLong("rows");
364 int cols
= GetLong("cols");
368 // fixed number of cells, need to verify children count
370 for ( wxXmlNode
*n
= m_node
->GetChildren(); n
; n
= n
->GetNext() )
372 if ( n
->GetType() == wxXML_ELEMENT_NODE
&&
373 (n
->GetName() == "object" || n
->GetName() == "object_ref") )
379 if ( children
> rows
* cols
)
385 "too many children in grid sizer: %d > %d x %d"
386 " (consider omitting the number of rows or columns)",
400 void wxSizerXmlHandler::SetFlexibleMode(wxFlexGridSizer
* fsizer
)
402 if (HasParam(wxT("flexibledirection")))
404 wxString dir
= GetParamValue(wxT("flexibledirection"));
406 if (dir
== wxT("wxVERTICAL"))
407 fsizer
->SetFlexibleDirection(wxVERTICAL
);
408 else if (dir
== wxT("wxHORIZONTAL"))
409 fsizer
->SetFlexibleDirection(wxHORIZONTAL
);
410 else if (dir
== wxT("wxBOTH"))
411 fsizer
->SetFlexibleDirection(wxBOTH
);
416 wxT("flexibledirection"),
417 wxString::Format("unknown direction \"%s\"", dir
)
422 if (HasParam(wxT("nonflexiblegrowmode")))
424 wxString mode
= GetParamValue(wxT("nonflexiblegrowmode"));
426 if (mode
== wxT("wxFLEX_GROWMODE_NONE"))
427 fsizer
->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_NONE
);
428 else if (mode
== wxT("wxFLEX_GROWMODE_SPECIFIED"))
429 fsizer
->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED
);
430 else if (mode
== wxT("wxFLEX_GROWMODE_ALL"))
431 fsizer
->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL
);
436 wxT("nonflexiblegrowmode"),
437 wxString::Format("unknown grow mode \"%s\"", mode
)
444 void wxSizerXmlHandler::SetGrowables(wxFlexGridSizer
* sizer
,
449 sizer
->CalcRowsCols(nrows
, ncols
);
450 const int nslots
= rows
? nrows
: ncols
;
452 wxStringTokenizer tkn
;
453 tkn
.SetString(GetParamValue(param
), wxT(","));
455 while (tkn
.HasMoreTokens())
458 wxString idxStr
= tkn
.GetNextToken().BeforeFirst(wxT(':'), &propStr
);
461 if (!idxStr
.ToULong(&li
))
466 "value must be a comma-separated list of numbers"
471 unsigned long lp
= 0;
472 if (!propStr
.empty())
474 if (!propStr
.ToULong(&lp
))
479 "value must be a comma-separated list of numbers"
485 const int n
= static_cast<int>(li
);
493 "invalid %s index %d: must be less than %d",
494 rows
? "row" : "column",
500 // ignore incorrect value, still try to process the rest
505 sizer
->AddGrowableRow(n
, static_cast<int>(lp
));
507 sizer
->AddGrowableCol(n
, static_cast<int>(lp
));
512 wxGBPosition
wxSizerXmlHandler::GetGBPos(const wxString
& param
)
514 wxSize sz
= GetSize(param
);
515 if (sz
.x
< 0) sz
.x
= 0;
516 if (sz
.y
< 0) sz
.y
= 0;
517 return wxGBPosition(sz
.x
, sz
.y
);
520 wxGBSpan
wxSizerXmlHandler::GetGBSpan(const wxString
& param
)
522 wxSize sz
= GetSize(param
);
523 if (sz
.x
< 1) sz
.x
= 1;
524 if (sz
.y
< 1) sz
.y
= 1;
525 return wxGBSpan(sz
.x
, sz
.y
);
530 wxSizerItem
* wxSizerXmlHandler::MakeSizerItem()
533 return new wxGBSizerItem();
535 return new wxSizerItem();
538 void wxSizerXmlHandler::SetSizerItemAttributes(wxSizerItem
* sitem
)
540 sitem
->SetProportion(GetLong(wxT("option"))); // Should this check for "proportion" too?
541 sitem
->SetFlag(GetStyle(wxT("flag")));
542 sitem
->SetBorder(GetDimension(wxT("border")));
543 wxSize sz
= GetSize(wxT("minsize"));
544 if (!(sz
== wxDefaultSize
))
545 sitem
->SetMinSize(sz
);
546 sz
= GetSize(wxT("ratio"));
547 if (!(sz
== wxDefaultSize
))
552 wxGBSizerItem
* gbsitem
= (wxGBSizerItem
*)sitem
;
553 gbsitem
->SetPos(GetGBPos(wxT("cellpos")));
554 gbsitem
->SetSpan(GetGBSpan(wxT("cellspan")));
557 // record the id of the item, if any, for use by XRCSIZERITEM()
558 sitem
->SetId(GetID());
561 void wxSizerXmlHandler::AddSizerItem(wxSizerItem
* sitem
)
564 ((wxGridBagSizer
*)m_parentSizer
)->Add((wxGBSizerItem
*)sitem
);
566 m_parentSizer
->Add(sitem
);
571 //-----------------------------------------------------------------------------
572 // wxStdDialogButtonSizerXmlHandler
573 //-----------------------------------------------------------------------------
576 IMPLEMENT_DYNAMIC_CLASS(wxStdDialogButtonSizerXmlHandler
, wxXmlResourceHandler
)
578 wxStdDialogButtonSizerXmlHandler::wxStdDialogButtonSizerXmlHandler()
579 : m_isInside(false), m_parentSizer(NULL
)
583 wxObject
*wxStdDialogButtonSizerXmlHandler::DoCreateResource()
585 if (m_class
== wxT("wxStdDialogButtonSizer"))
587 wxASSERT( !m_parentSizer
);
589 wxSizer
*s
= m_parentSizer
= new wxStdDialogButtonSizer
;
592 CreateChildren(m_parent
, true/*only this handler*/);
594 m_parentSizer
->Realize();
597 m_parentSizer
= NULL
;
601 else // m_class == "button"
603 wxASSERT( m_parentSizer
);
605 // find the item to be managed by this sizeritem
606 wxXmlNode
*n
= GetParamNode(wxT("object"));
608 n
= GetParamNode(wxT("object_ref"));
613 wxObject
*item
= CreateResFromNode(n
, m_parent
, NULL
);
614 wxButton
*button
= wxDynamicCast(item
, wxButton
);
617 m_parentSizer
->AddButton(button
);
619 ReportError(n
, "expected wxButton");
625 ReportError("no button within wxStdDialogButtonSizer");
631 bool wxStdDialogButtonSizerXmlHandler::CanHandle(wxXmlNode
*node
)
633 return (!m_isInside
&& IsOfClass(node
, wxT("wxStdDialogButtonSizer"))) ||
634 (m_isInside
&& IsOfClass(node
, wxT("button")));
636 #endif // wxUSE_BUTTON