X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f80ea77b4a8bac4ab005bfc592f9cd3262ffa397..07aaf32633ecf18ec3edfbb41793a112914792d0:/src/xrc/xh_sizer.cpp diff --git a/src/xrc/xh_sizer.cpp b/src/xrc/xh_sizer.cpp index 1163ab619f..b0dd955f44 100644 --- a/src/xrc/xh_sizer.cpp +++ b/src/xrc/xh_sizer.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: xh_sizer.cpp +// Name: src/xrc/xh_sizer.cpp // Purpose: XRC resource for wxBoxSizer // Author: Vaclav Slavik // Created: 2000/03/21 @@ -8,10 +8,6 @@ // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// -#ifdef __GNUG__ -#pragma implementation "xh_sizer.h" -#endif - // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" @@ -19,26 +15,39 @@ #pragma hdrstop #endif +#if wxUSE_XRC + #include "wx/xrc/xh_sizer.h" -#include "wx/sizer.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/panel.h" + #include "wx/statbox.h" + #include "wx/sizer.h" + #include "wx/frame.h" + #include "wx/dialog.h" + #include "wx/button.h" + #include "wx/scrolwin.h" +#endif + #include "wx/gbsizer.h" -#include "wx/log.h" -#include "wx/statbox.h" +#include "wx/wrapsizer.h" #include "wx/notebook.h" -#include "wx/panel.h" #include "wx/tokenzr.h" +#include "wx/xml/xml.h" +//----------------------------------------------------------------------------- +// wxSizerXmlHandler +//----------------------------------------------------------------------------- IMPLEMENT_DYNAMIC_CLASS(wxSizerXmlHandler, wxXmlResourceHandler) - - wxSizerXmlHandler::wxSizerXmlHandler() - : wxXmlResourceHandler(), - m_isInside(false), - m_isGBS(false), - m_parentSizer(NULL) + :wxXmlResourceHandler(), + m_isInside(false), + m_isGBS(false), + m_parentSizer(NULL) { XRC_ADD_STYLE(wxHORIZONTAL); XRC_ADD_STYLE(wxVERTICAL); @@ -70,8 +79,17 @@ wxSizerXmlHandler::wxSizerXmlHandler() XRC_ADD_STYLE(wxALIGN_CENTER_VERTICAL); XRC_ADD_STYLE(wxALIGN_CENTRE_VERTICAL); - XRC_ADD_STYLE(wxADJUST_MINSIZE); XRC_ADD_STYLE(wxFIXED_MINSIZE); + XRC_ADD_STYLE(wxRESERVE_SPACE_EVEN_IF_HIDDEN); + + // this flag doesn't do anything any more but we can just ignore its + // occurrences in the old resource files instead of raising a fuss because + // of it + AddStyle("wxADJUST_MINSIZE", 0); + + // wxWrapSizer-specific flags + XRC_ADD_STYLE(wxEXTEND_LAST_ON_EACH_LINE); + XRC_ADD_STYLE(wxREMOVE_LEADING_SPACES); } @@ -98,15 +116,47 @@ wxObject* wxSizerXmlHandler::DoCreateResource() } +wxSizer* wxSizerXmlHandler::DoCreateSizer(const wxString& name) +{ + if (name == wxT("wxBoxSizer")) + return Handle_wxBoxSizer(); +#if wxUSE_STATBOX + else if (name == wxT("wxStaticBoxSizer")) + return Handle_wxStaticBoxSizer(); +#endif + else if (name == wxT("wxGridSizer")) + { + if ( !ValidateGridSizerChildren() ) + return NULL; + return Handle_wxGridSizer(); + } + else if (name == wxT("wxFlexGridSizer")) + { + return Handle_wxFlexGridSizer(); + } + else if (name == wxT("wxGridBagSizer")) + { + return Handle_wxGridBagSizer(); + } + else if (name == wxT("wxWrapSizer")) + { + return Handle_wxWrapSizer(); + } + + ReportError(wxString::Format("unknown sizer class \"%s\"", name)); + return NULL; +} + -bool wxSizerXmlHandler::IsSizerNode(wxXmlNode *node) +bool wxSizerXmlHandler::IsSizerNode(wxXmlNode *node) const { return (IsOfClass(node, wxT("wxBoxSizer"))) || (IsOfClass(node, wxT("wxStaticBoxSizer"))) || (IsOfClass(node, wxT("wxGridSizer"))) || (IsOfClass(node, wxT("wxFlexGridSizer"))) || - (IsOfClass(node, wxT("wxGridBagSizer"))); + (IsOfClass(node, wxT("wxGridBagSizer"))) || + (IsOfClass(node, wxT("wxWrapSizer"))); } @@ -139,11 +189,11 @@ wxObject* wxSizerXmlHandler::Handle_sizeritem() wxWindow *wnd = wxDynamicCast(item, wxWindow); if (sizer) - sitem->SetSizer(sizer); + sitem->AssignSizer(sizer); else if (wnd) - sitem->SetWindow(wnd); + sitem->AssignWindow(wnd); else - wxLogError(wxT("Error in resource.")); + ReportError(n, "unexpected item in sizer"); // finally, set other wxSizerItem attributes SetSizerItemAttributes(sitem); @@ -153,7 +203,7 @@ wxObject* wxSizerXmlHandler::Handle_sizeritem() } else /*n == NULL*/ { - wxLogError(wxT("Error in resource: no window/sizer/spacer within sizeritem object.")); + ReportError("no window/sizer/spacer within sizeritem object"); return NULL; } } @@ -161,11 +211,15 @@ wxObject* wxSizerXmlHandler::Handle_sizeritem() wxObject* wxSizerXmlHandler::Handle_spacer() { - wxCHECK_MSG(m_parentSizer, NULL, wxT("Incorrect syntax of XRC resource: spacer not within sizer!")); + if ( !m_parentSizer ) + { + ReportError("spacer only allowed inside a sizer"); + return NULL; + } wxSizerItem* sitem = MakeSizerItem(); SetSizerItemAttributes(sitem); - sitem->SetSpacer(GetSize()); + sitem->AssignSpacer(GetSize()); AddSizerItem(sitem); return NULL; } @@ -173,34 +227,22 @@ wxObject* wxSizerXmlHandler::Handle_spacer() wxObject* wxSizerXmlHandler::Handle_sizer() { - wxSizer *sizer = NULL; - wxXmlNode *parentNode = m_node->GetParent(); - wxCHECK_MSG(m_parentSizer != NULL || - (parentNode && parentNode->GetType() == wxXML_ELEMENT_NODE && - m_parentAsWindow != NULL && - (m_parentAsWindow->IsKindOf(CLASSINFO(wxPanel)) || - m_parentAsWindow->IsKindOf(CLASSINFO(wxFrame)) || - m_parentAsWindow->IsKindOf(CLASSINFO(wxDialog))) - ), NULL, - wxT("Incorrect use of sizer: parent is not 'wxDialog', 'wxFrame' or 'wxPanel'.")); - - if (m_class == wxT("wxBoxSizer")) - sizer = Handle_wxBoxSizer(); - - else if (m_class == wxT("wxStaticBoxSizer")) - sizer = Handle_wxStaticBoxSizer(); - - else if (m_class == wxT("wxGridSizer")) - sizer = Handle_wxGridSizer(); - - else if (m_class == wxT("wxFlexGridSizer")) - sizer = Handle_wxFlexGridSizer(); + if ( !m_parentSizer && + (!parentNode || parentNode->GetType() != wxXML_ELEMENT_NODE || + !m_parentAsWindow) ) + { + ReportError("sizer must have a window parent"); + return NULL; + } - else if (m_class == wxT("wxGridBagSizer")) - sizer = Handle_wxGridBagSizer(); + // Create the sizer of the appropriate class. + wxSizer * const sizer = DoCreateSizer(m_class); + // creation of sizer failed for some (already reported) reason, so exit: + if ( !sizer ) + return NULL; wxSize minsize = GetSize(wxT("minsize")); if (!(minsize == wxDefaultSize)) @@ -215,7 +257,24 @@ wxObject* wxSizerXmlHandler::Handle_sizer() m_isInside = true; m_isGBS = (m_class == wxT("wxGridBagSizer")); - CreateChildren(m_parent, true/*only this handler*/); + wxObject* parent = m_parent; +#if wxUSE_STATBOX + // wxStaticBoxSizer's child controls should be parented by the box itself, + // not its parent. + wxStaticBoxSizer* const stsizer = wxDynamicCast(sizer, wxStaticBoxSizer); + if ( stsizer ) + parent = stsizer->GetStaticBox(); +#endif // wxUSE_STATBOX + + CreateChildren(parent, true/*only this handler*/); + + // set growable rows and cols for sizers which support this + if ( wxFlexGridSizer *flexsizer = wxDynamicCast(sizer, wxFlexGridSizer) ) + { + SetFlexibleMode(flexsizer); + SetGrowables(flexsizer, wxT("growablerows"), true); + SetGrowables(flexsizer, wxT("growablecols"), false); + } // restore state m_isInside = old_ins; @@ -223,17 +282,27 @@ wxObject* wxSizerXmlHandler::Handle_sizer() if (m_parentSizer == NULL) // setup window: { - m_parentAsWindow->SetAutoLayout(true); m_parentAsWindow->SetSizer(sizer); wxXmlNode *nd = m_node; m_node = parentNode; if (GetSize() == wxDefaultSize) - sizer->Fit(m_parentAsWindow); + { + if ( wxDynamicCast(m_parentAsWindow, wxScrolledWindow) != NULL ) + { + sizer->FitInside(m_parentAsWindow); + } + else + { + sizer->Fit(m_parentAsWindow); + } + } m_node = nd; - if (m_parentAsWindow->GetWindowStyle() & (wxRESIZE_BOX | wxRESIZE_BORDER)) + if (m_parentAsWindow->IsTopLevel()) + { sizer->SetSizeHints(m_parentAsWindow); + } } return sizer; @@ -245,6 +314,7 @@ wxSizer* wxSizerXmlHandler::Handle_wxBoxSizer() return new wxBoxSizer(GetStyle(wxT("orient"), wxHORIZONTAL)); } +#if wxUSE_STATBOX wxSizer* wxSizerXmlHandler::Handle_wxStaticBoxSizer() { return new wxStaticBoxSizer( @@ -256,6 +326,7 @@ wxSizer* wxSizerXmlHandler::Handle_wxStaticBoxSizer() GetName()), GetStyle(wxT("orient"), wxHORIZONTAL)); } +#endif // wxUSE_STATBOX wxSizer* wxSizerXmlHandler::Handle_wxGridSizer() { @@ -264,46 +335,176 @@ wxSizer* wxSizerXmlHandler::Handle_wxGridSizer() } -wxSizer* wxSizerXmlHandler::Handle_wxFlexGridSizer() +wxFlexGridSizer* wxSizerXmlHandler::Handle_wxFlexGridSizer() { - wxFlexGridSizer *sizer = - new wxFlexGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")), - GetDimension(wxT("vgap")), GetDimension(wxT("hgap"))); - SetGrowables(sizer, wxT("growablerows"), true); - SetGrowables(sizer, wxT("growablecols"), false); - return sizer; + if ( !ValidateGridSizerChildren() ) + return NULL; + return new wxFlexGridSizer(GetLong(wxT("rows")), GetLong(wxT("cols")), + GetDimension(wxT("vgap")), GetDimension(wxT("hgap"))); } -wxSizer* wxSizerXmlHandler::Handle_wxGridBagSizer() +wxGridBagSizer* wxSizerXmlHandler::Handle_wxGridBagSizer() { - wxGridBagSizer *sizer = - new wxGridBagSizer(GetDimension(wxT("vgap")), GetDimension(wxT("hgap"))); - SetGrowables(sizer, wxT("growablerows"), true); - SetGrowables(sizer, wxT("growablecols"), false); + if ( !ValidateGridSizerChildren() ) + return NULL; + return new wxGridBagSizer(GetDimension(wxT("vgap")), GetDimension(wxT("hgap"))); +} + +wxSizer* wxSizerXmlHandler::Handle_wxWrapSizer() +{ + wxWrapSizer *sizer = new wxWrapSizer(GetStyle("orient"), GetStyle("flag")); return sizer; } +bool wxSizerXmlHandler::ValidateGridSizerChildren() +{ + int rows = GetLong("rows"); + int cols = GetLong("cols"); + + if ( rows && cols ) + { + // fixed number of cells, need to verify children count + int children = 0; + for ( wxXmlNode *n = m_node->GetChildren(); n; n = n->GetNext() ) + { + if ( n->GetType() == wxXML_ELEMENT_NODE && + (n->GetName() == "object" || n->GetName() == "object_ref") ) + { + children++; + } + } + + if ( children > rows * cols ) + { + ReportError + ( + wxString::Format + ( + "too many children in grid sizer: %d > %d x %d" + " (consider omitting the number of rows or columns)", + children, + cols, + rows + ) + ); + return false; + } + } + + return true; +} + + +void wxSizerXmlHandler::SetFlexibleMode(wxFlexGridSizer* fsizer) +{ + if (HasParam(wxT("flexibledirection"))) + { + wxString dir = GetParamValue(wxT("flexibledirection")); + + if (dir == wxT("wxVERTICAL")) + fsizer->SetFlexibleDirection(wxVERTICAL); + else if (dir == wxT("wxHORIZONTAL")) + fsizer->SetFlexibleDirection(wxHORIZONTAL); + else if (dir == wxT("wxBOTH")) + fsizer->SetFlexibleDirection(wxBOTH); + else + { + ReportParamError + ( + wxT("flexibledirection"), + wxString::Format("unknown direction \"%s\"", dir) + ); + } + } + + if (HasParam(wxT("nonflexiblegrowmode"))) + { + wxString mode = GetParamValue(wxT("nonflexiblegrowmode")); + + if (mode == wxT("wxFLEX_GROWMODE_NONE")) + fsizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_NONE); + else if (mode == wxT("wxFLEX_GROWMODE_SPECIFIED")) + fsizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED); + else if (mode == wxT("wxFLEX_GROWMODE_ALL")) + fsizer->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_ALL); + else + { + ReportParamError + ( + wxT("nonflexiblegrowmode"), + wxString::Format("unknown grow mode \"%s\"", mode) + ); + } + } +} void wxSizerXmlHandler::SetGrowables(wxFlexGridSizer* sizer, const wxChar* param, bool rows) { + int nrows, ncols; + sizer->CalcRowsCols(nrows, ncols); + const int nslots = rows ? nrows : ncols; + wxStringTokenizer tkn; - unsigned long l; tkn.SetString(GetParamValue(param), wxT(",")); + while (tkn.HasMoreTokens()) { - if (!tkn.GetNextToken().ToULong(&l)) - wxLogError(wxT("growable[rows|cols] must be comma-separated list of row numbers")); - else { - if (rows) - sizer->AddGrowableRow(l); - else - sizer->AddGrowableCol(l); + wxString propStr; + wxString idxStr = tkn.GetNextToken().BeforeFirst(wxT(':'), &propStr); + + unsigned long li; + if (!idxStr.ToULong(&li)) + { + ReportParamError + ( + param, + "value must be a comma-separated list of numbers" + ); + break; } + + unsigned long lp = 0; + if (!propStr.empty()) + { + if (!propStr.ToULong(&lp)) + { + ReportParamError + ( + param, + "value must be a comma-separated list of numbers" + ); + break; + } + } + + const int n = static_cast(li); + if ( n >= nslots ) + { + ReportParamError + ( + param, + wxString::Format + ( + "invalid %s index %d: must be less than %d", + rows ? "row" : "column", + n, + nslots + ) + ); + + // ignore incorrect value, still try to process the rest + continue; + } + + if (rows) + sizer->AddGrowableRow(n, static_cast(lp)); + else + sizer->AddGrowableCol(n, static_cast(lp)); } } @@ -352,6 +553,9 @@ void wxSizerXmlHandler::SetSizerItemAttributes(wxSizerItem* sitem) gbsitem->SetPos(GetGBPos(wxT("cellpos"))); gbsitem->SetSpan(GetGBSpan(wxT("cellspan"))); } + + // record the id of the item, if any, for use by XRCSIZERITEM() + sitem->SetId(GetID()); } void wxSizerXmlHandler::AddSizerItem(wxSizerItem* sitem) @@ -364,10 +568,71 @@ void wxSizerXmlHandler::AddSizerItem(wxSizerItem* sitem) +//----------------------------------------------------------------------------- +// wxStdDialogButtonSizerXmlHandler +//----------------------------------------------------------------------------- +#if wxUSE_BUTTON +IMPLEMENT_DYNAMIC_CLASS(wxStdDialogButtonSizerXmlHandler, wxXmlResourceHandler) +wxStdDialogButtonSizerXmlHandler::wxStdDialogButtonSizerXmlHandler() + : m_isInside(false), m_parentSizer(NULL) +{ +} +wxObject *wxStdDialogButtonSizerXmlHandler::DoCreateResource() +{ + if (m_class == wxT("wxStdDialogButtonSizer")) + { + wxASSERT( !m_parentSizer ); + + wxSizer *s = m_parentSizer = new wxStdDialogButtonSizer; + m_isInside = true; + + CreateChildren(m_parent, true/*only this handler*/); + m_parentSizer->Realize(); + m_isInside = false; + m_parentSizer = NULL; + return s; + } + else // m_class == "button" + { + wxASSERT( m_parentSizer ); + + // find the item to be managed by this sizeritem + wxXmlNode *n = GetParamNode(wxT("object")); + if ( !n ) + n = GetParamNode(wxT("object_ref")); + + // did we find one? + if (n) + { + wxObject *item = CreateResFromNode(n, m_parent, NULL); + wxButton *button = wxDynamicCast(item, wxButton); + + if (button) + m_parentSizer->AddButton(button); + else + ReportError(n, "expected wxButton"); + + return item; + } + else /*n == NULL*/ + { + ReportError("no button within wxStdDialogButtonSizer"); + return NULL; + } + } +} + +bool wxStdDialogButtonSizerXmlHandler::CanHandle(wxXmlNode *node) +{ + return (!m_isInside && IsOfClass(node, wxT("wxStdDialogButtonSizer"))) || + (m_isInside && IsOfClass(node, wxT("button"))); +} +#endif // wxUSE_BUTTON +#endif // wxUSE_XRC