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