DIM_3D
};
+ typedef sequence<string> ListOfParameters;
+
interface SMESH_Hypothesis : SALOME::GenericObj
{
+
/*!
* Get the Hypothesis typeName
*/
* Return list of notebook variables used for Hypothesis creation separated by ":" symbol
*/
string GetParameters();
-
+
+ /*!
+ * Return list of last notebook variables used for Hypothesis creation.
+ */
+ ListOfParameters GetLastParameters();
+
/*!
* Verify whether hypothesis supports given entity type
*/
return NULL;
}
+//=============================================================================
+/*!
+ *
+ */
+//=============================================================================
+char* SMESHGUI::JoinObjectParameters(const QStringList& theParametersList)
+{
+ return theParametersList.join(":").toLatin1().data();
+}
+
//=============================================================================
/*!
*
static SUIT_ResourceMgr* resourceMgr();
static SUIT_Desktop* desktop();
static SalomeApp_Study* activeStudy();
+ static char* JoinObjectParameters(const QStringList& theParametersList);
+
bool isActiveStudyLocked();
static bool automaticUpdate();
w = sb;
}
else if(aStudy->IsReal(aVar.toLatin1().constData())){
- SalomeApp_DoubleSpinBox* sb = new SMESHGUI_SpinBox( GroupC1 );
+ SalomeApp_DoubleSpinBox* sb = new SalomeApp_DoubleSpinBox( GroupC1 );
sb->setObjectName( (*anIt).myName );
attuneStdWidget( sb, i );
sb->setText( aVar );
QStringList SMESHGUI_GenericHypothesisCreator::getVariablesFromDlg() const
{
QStringList aResult;
- QString item;
- _PTR(Study) aStudy = SMESH::GetActiveStudyDocument();
- if(aStudy) {
- ListOfWidgets::const_iterator anIt = widgets().begin(), aLast = widgets().end();
- for( ; anIt!=aLast; anIt++ ) {
- if( (*anIt)->inherits( "SalomeApp_IntSpinBox" ) )
- {
- SalomeApp_IntSpinBox* sb = ( SalomeApp_IntSpinBox* )( *anIt );
- item = sb->text();
- bool isVariable = aStudy->IsVariable(item.toLatin1().constData());
- isVariable ? aResult.append( item ) : aResult.append(QString());
- }
-
- else if( (*anIt)->inherits( "QtxDoubleSpinBox" ) )
- {
- QtxDoubleSpinBox* sb = ( QtxDoubleSpinBox* )( *anIt );
- item = sb->text();
- bool isVariable = aStudy->IsVariable(item.toLatin1().constData());
- isVariable ? aResult.append( item ) : aResult.append(QString());
- }
- }
- bool hasVar = false;
- for (int i = 0;i<aResult.size();i++)
- if(!aResult[i].isEmpty())
- hasVar = true;
-
- if(!hasVar)
- aResult.clear();
+ ListOfWidgets::const_iterator anIt = widgets().begin(), aLast = widgets().end();
+ for( ; anIt!=aLast; anIt++ ) {
+ if( (*anIt)->inherits( "SalomeApp_IntSpinBox" ) ) {
+ SalomeApp_IntSpinBox* sb = ( SalomeApp_IntSpinBox* )( *anIt );
+ aResult.append(sb->text());
+ }
+ else if( (*anIt)->inherits( "QtxDoubleSpinBox" ) ) {
+ QtxDoubleSpinBox* sb = ( QtxDoubleSpinBox* )( *anIt );
+ aResult.append(sb->text());
+ }
}
return aResult;
}
void UpdateParameters(CORBA::Object_ptr theObject, const char* theParameters);
char* GetParameters(CORBA::Object_ptr theObject);
+
private:
// Create hypothesis of given type
if ( !aHyp->_is_nil() ) {
CORBA::String_var objStr = aHyp->GetParameters();
- TCollection_AsciiString aParams(theParameters);
- if(aParams.Length()) {
- SALOMEDS::GenericAttribute_var anAttr;
- anAttr = aStudyBuilder->FindOrCreateAttribute( aSObj, "AttributeString");
- SALOMEDS::AttributeString::_narrow(anAttr)->SetValue( aParams.ToCString() );
+ TCollection_AsciiString aNewParams;
+ TCollection_AsciiString anInputParams;
+ SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(theParameters);
+
+ SALOMEDS::GenericAttribute_var anAttr;
+ anAttr = aStudyBuilder->FindOrCreateAttribute( aSObj, "AttributeString");
+ SALOMEDS::AttributeString_var aStringAttr = SALOMEDS::AttributeString::_narrow(anAttr);
+ TCollection_AsciiString aOldParameters(aStringAttr->Value());
+ SALOMEDS::ListOfStrings aVars= aSections[0];
+ for(int i=0;i<aVars.length();i++ ) {
+ anInputParams += aStudy->IsVariable(aVars[i].in()) ?
+ TCollection_AsciiString(aVars[i].in()) : TCollection_AsciiString("");
+ if(i != aVars.length()-1)
+ anInputParams+=":";
}
- else
- aStudyBuilder->RemoveAttribute(aSObj,"AttributeString");
+ if(!aOldParameters.Length())
+ aNewParams = anInputParams;
+ else
+ aNewParams = aOldParameters+"|"+anInputParams;
+
+ aStringAttr->SetValue( aNewParams.ToCString() );
}
}
//=============================================================================
void SMESH_Hypothesis_i::SetParameters(const char* theParameters)
{
- string aNewParameters(theParameters);
- string anOldParameters(GetParameters());
- if(aNewParameters.compare(anOldParameters) != 0)
- SMESH_Gen_i::GetSMESHGen()->UpdateParameters(SMESH::SMESH_Hypothesis::_narrow(_this()),
- theParameters);
+ SMESH_Gen_i::GetSMESHGen()->UpdateParameters(SMESH::SMESH_Hypothesis::_narrow(_this()),
+ CORBA::string_dup(theParameters));
}
+//=============================================================================
+/*!
+ * SMESH_Hypothesis_i::GetParameters()
+ *
+ */
+//=============================================================================
char* SMESH_Hypothesis_i::GetParameters()
{
SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
return CORBA::string_dup(gen->GetParameters(SMESH::SMESH_Hypothesis::_narrow(_this())));
}
+//=============================================================================
+/*!
+ * SMESH_Hypothesis_i::GetLastParameters()
+ *
+ */
+//=============================================================================
+SMESH::ListOfParameters* SMESH_Hypothesis_i::GetLastParameters()
+{
+ SMESH::ListOfParameters_var aResult = new SMESH::ListOfParameters();
+ SMESH_Gen_i *gen = SMESH_Gen_i::GetSMESHGen();
+ if(gen) {
+ char *aParameters = GetParameters();
+ SALOMEDS::Study_ptr aStudy = gen->GetCurrentStudy();
+ if(!aStudy->_is_nil()) {
+ SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters);
+ if(aSections->length() > 0) {
+ SALOMEDS::ListOfStrings aVars = aSections[aSections->length()-1];
+ aResult->length(aVars.length());
+ for(int i = 0;i < aVars.length();i++)
+ aResult[i] = CORBA::string_dup( aVars[i]);
+ }
+ }
+ }
+ return aResult._retn();
+}
+
//=============================================================================
/*!
* SMESH_Hypothesis_i::GetImpl
// Return list of notebook variables used for Hypothesis creation separated by ":" symbol
char* GetParameters();
+
+ //Return list of last notebook variables used for Hypothesis creation.
+ SMESH::ListOfParameters* GetLastParameters();
// Get implementation
::SMESH_Hypothesis* GetImpl();
using namespace std;
+
+
+//================================================================================
+/*!
+ * \brief Constructor
+ */
+//================================================================================
+ObjectStates::ObjectStates(TCollection_AsciiString theType)
+{
+ _type = theType;
+ _dumpstate = 0;
+}
+
+//================================================================================
+/*!
+ * \brief Destructor
+ */
+//================================================================================
+ObjectStates::~ObjectStates()
+{
+}
+
+//================================================================================
+/*!
+ * \brief Add new object state
+ * \param theState - Object state (vector of notebook variable)
+ */
+//================================================================================
+void ObjectStates::AddState(const TState &theState)
+{
+ _states.push_back(theState);
+}
+
+//================================================================================
+/*!
+ * \brief Return current object state
+ * \\retval state - Object state (vector of notebook variable)
+ */
+//================================================================================
+TState ObjectStates::GetCurrectState() const
+{
+ return _states[_dumpstate];
+}
+
+
+//================================================================================
+/*!
+ *
+ */
+//================================================================================
+TAllStates ObjectStates::GetAllStates() const
+{
+ return _states;
+}
+
+//================================================================================
+/*!
+ *
+ */
+//================================================================================
+void ObjectStates::IncrementState()
+{
+ _dumpstate++;
+}
+
+//================================================================================
+/*!
+ *
+ */
+//================================================================================
+TCollection_AsciiString ObjectStates::GetObjectType() const{
+ return _type;
+}
+
//================================================================================
/*!
* \brief Constructor
//================================================================================
/*!
- * \brief Constructor
+ * \brief Destructor
*/
//================================================================================
SMESH_NoteBook::~SMESH_NoteBook()
{
+ TVariablesMap::const_iterator it = _objectMap.begin();
+ for(;it!=_objectMap.end();it++) {
+ if((*it).second)
+ delete (*it).second;
+ }
}
//================================================================================
TCollection_AsciiString aObject = aCmd.GetObject();
TVariablesMap::const_iterator it = _objectMap.find(aObject);
if(!aMethod.IsEmpty() && it != _objectMap.end() ) {
-
- if(aMethod == "SetLength" && !(*it).second.at(0).IsEmpty() ) {
- aCmd.SetArg(1,(*it).second.at(0));
- }
- else if(aMethod == "SetPrecision" && !(*it).second.at(1).IsEmpty() ){
- aCmd.SetArg(1,(*it).second.at(1));
+ ObjectStates *aStates = (*it).second;
+ bool modified = false;
+ if(MYDEBUG)
+ cout<<"SMESH_NoteBook::ReplaceVariables :Object Type : "<<aStates->GetObjectType()<<endl;
+ if(aStates->GetObjectType().IsEqual("LocalLength")) {
+ if(aMethod == "SetLength") {
+ if(!aStates->GetCurrectState().at(0).IsEmpty() )
+ aCmd.SetArg(1,aStates->GetCurrectState().at(0));
+ aStates->IncrementState();
+ }
+ else if(aMethod == "SetPrecision") {
+ if(!aStates->GetCurrectState().at(1).IsEmpty() )
+ aCmd.SetArg(1,aStates->GetCurrectState().at(1));
+ aStates->IncrementState();
+ }
}
return aCmd.GetString();
}
SALOMEDS::SObject_var aSO = aStudy->FindComponent(aGen->ComponentDataType());
if(CORBA::is_nil(aSO))
return;
-
+
SALOMEDS::ChildIterator_var Itr = aStudy->NewChildIterator(aSO);
- TCollection_AsciiString aParameters;
+ char* aParameters;
for(Itr->InitEx(true); Itr->More(); Itr->Next()) {
SALOMEDS::SObject_var aSObject = Itr->Value();
SALOMEDS::GenericAttribute_var anAttr;
if ( aSObject->FindAttribute(anAttr, "AttributeString")) {
- aParameters = TCollection_AsciiString(SALOMEDS::AttributeString::_narrow(anAttr)->Value());
- vector<string> vect = ParseVariables(aParameters.ToCString(),':');
+ aParameters = SALOMEDS::AttributeString::_narrow(anAttr)->Value();
+ SALOMEDS::ListOfListOfStrings_var aSections = aStudy->ParseVariables(aParameters);
if(MYDEBUG) {
cout<<"Entry : "<< aSObject->GetID()<<endl;
cout<<"aParameters : "<<aParameters<<endl;
+ }
+ TCollection_AsciiString anObjType;
+ CORBA::Object_var anObject = SMESH_Gen_i::SObjectToObject(aSObject);
+ SMESH::SMESH_Hypothesis_var aHyp = SMESH::SMESH_Hypothesis::_narrow(anObject);
+ if(!aHyp->_is_nil()) {
+ anObjType = TCollection_AsciiString(aHyp->GetName());
}
- vector<TCollection_AsciiString> aVars;
- for(int i = 0;i<vect.size();i++) {
- TCollection_AsciiString aVar(vect[i].c_str());
- if(!aVar.IsEmpty() && aStudy->IsVariable(vect[i].c_str())) {
- aVar.InsertBefore(1,"\"");
- aVar.InsertAfter(aVar.Length(),"\"");
- }
- aVars.push_back(aVar);
- if(MYDEBUG) {
- cout<<"Variable: "<<aVar<<endl;
+ else if(SMESH::SMESH_Mesh_var aMesh = SMESH::SMESH_Mesh::_narrow(anObject)) {
+ anObjType = TCollection_AsciiString("Mesh");
+ }
+ if(MYDEBUG)
+ cout<<"The object Type : "<<anObjType<<endl;
+
+ ObjectStates *aState = new ObjectStates(anObjType);
+ for(int i = 0; i < aSections->length(); i++) {
+ TState aVars;
+ SALOMEDS::ListOfStrings aListOfVars = aSections[i];
+ for(int j = 0;j<aListOfVars.length();j++) {
+ TCollection_AsciiString aVar(aListOfVars[j].in());
+ if(!aVar.IsEmpty() && aStudy->IsVariable(aVar.ToCString())) {
+ aVar.InsertBefore(1,"\"");
+ aVar.InsertAfter(aVar.Length(),"\"");
+ }
+ aVars.push_back(aVar);
+ if(MYDEBUG) {
+ cout<<"Variable: '"<<aVar<<"'"<<endl;
+ }
}
+ aState->AddState(aVars);
}
- _objectMap.insert(pair<TCollection_AsciiString,vector<TCollection_AsciiString> >(TCollection_AsciiString(aSObject->GetID()),aVars));
+ _objectMap.insert(pair<TCollection_AsciiString,ObjectStates*>(TCollection_AsciiString(aSObject->GetID()),aState));
}
}
}
-
-//================================================================================
-/*!
- * \brief Private method
- */
-//================================================================================
-vector<string> SMESH_NoteBook::ParseVariables(const string& theVariables, const char sep) const
-{
- vector<string> aResult;
- if(theVariables[0] == sep ) aResult.push_back(string());
- int pos = theVariables.find(sep);
- if(pos < 0) {
- aResult.push_back(theVariables);
- return aResult;
- }
-
- string s = theVariables;
- if(s[0] == sep) s = s.substr(1, s.size());
- while((pos = s.find(sep)) >= 0) {
- aResult.push_back(s.substr(0, pos));
- s = s.substr(pos+1, s.size());
- }
-
- if(!s.empty() && s[0] != sep) aResult.push_back(s);
- if(theVariables[theVariables.size()-1] == sep) aResult.push_back(string());
-
- return aResult;
-}
#include <vector>
#include <string>
+typedef std::vector<TCollection_AsciiString> TState;
+typedef std::vector<TState> TAllStates;
+
+class ObjectStates{
+
+public:
+
+ ObjectStates(TCollection_AsciiString theType);
+ ~ObjectStates();
+
+ void AddState(const TState &theState);
+
+ TState GetCurrectState() const;
+ TAllStates GetAllStates() const;
+ void IncrementState();
+ TCollection_AsciiString GetObjectType() const;
+
+
+
+private:
+ TCollection_AsciiString _type;
+ TAllStates _states;
+ int _dumpstate;
+};
class SMESH_NoteBook
{
~SMESH_NoteBook();
TCollection_AsciiString ReplaceVariables(const TCollection_AsciiString& theString) const;
- typedef std::map<TCollection_AsciiString,std::vector<TCollection_AsciiString> > TVariablesMap;
+ typedef std::map<TCollection_AsciiString,ObjectStates*> TVariablesMap;
private:
void InitObjectMap();
- std::vector<std::string> ParseVariables(const std::string& theVariables, const char sep) const;
private:
TVariablesMap _objectMap;
PrecisionConfusion = 1e-07
+# Salome notebook variable separator
+variable_separator = ":"
+
def IsEqual(val1, val2, tol=PrecisionConfusion):
if abs(val1 - val2) < tol:
return True
## Gets object name
def GetName(obj):
- if isinstance(obj, BaseWrapper):
- obj = obj.GetAlgorithm()
ior = salome.orb.object_to_string(obj)
sobj = salome.myStudy.FindObjectIOR(ior)
if sobj is None:
## Sets a name to the object
def SetName(obj, name):
- if isinstance(obj, BaseWrapper):
- obj = obj.GetAlgorithm()
ior = salome.orb.object_to_string(obj)
sobj = salome.myStudy.FindObjectIOR(ior)
if not sobj is None:
aMesh = Mesh(self, self.geompyD, aSmeshMesh)
return aMesh
- ## Create hyporthesis
- # @return an instance of hypothesis
- # @ingroup l2_impexp
- def CreateHypothesis(self, hyp, so):
- hypo = SMESH._objref_SMESH_Gen.CreateHypothesis(self, hyp, so)
- if hyp == "LocalLength":
- hypo = LocalLength(hypo)
-
- return hypo
-
-
## Creates a Mesh object(s) importing data from the given MED file
# @return a list of Mesh class instances
# @ingroup l2_impexp
# @return SMESH.Hypothesis_Status
# @ingroup l2_hypotheses
def AddHypothesis(self, hyp, geom=0):
- if isinstance( hyp, Mesh_Algorithm ) or isinstance( hyp, BaseWrapper):
+ if isinstance( hyp, Mesh_Algorithm ):
hyp = hyp.GetAlgorithm()
pass
if not geom:
# @return SMESH.Hypothesis_Status
# @ingroup l2_hypotheses
def RemoveHypothesis(self, hyp, geom=0):
- if isinstance( hyp, Mesh_Algorithm ) or isinstance( hyp, BaseWrapper):
+ if isinstance( hyp, Mesh_Algorithm ):
hyp = hyp.GetAlgorithm()
pass
if not geom:
pass
SetName(hypo, hyp + a)
pass
- bhypo = None
- if isinstance(hypo,BaseWrapper):
- bhypo = hypo.GetAlgorithm()
- else:
- bhypo = hypo
- status = self.mesh.mesh.AddHypothesis(self.geom, bhypo)
+ status = self.mesh.mesh.AddHypothesis(self.geom, hypo)
TreatHypoStatus( status, GetName(hypo), GetName(self.geom), 0 )
return hypo
self.Create(mesh, geom, "UseExisting_2D")
+import salome_notebook
+notebook = salome_notebook.notebook
-
-from salome_notebook import *
-
-##Base class for wrap all StdMeshers interfaces
-class BaseWrapper:
-
- ##Return instance of a _objref_StdMeshers hypothesis
- def GetAlgorithm(self):
- return self.hypo
-
- ##Return values of the notebook variables
- def ParseParameters(self, params ,nbParams, nbParam, arg):
- result = None
- strResult = ""
- isVar = False
- if isinstance(arg, str):
- if notebook.isVariable(arg):
- result = notebook.get(arg)
- isVar = True
+##Return values of the notebook variables
+def ParseParameters(last, nbParams,nbParam, value):
+ result = None
+ strResult = ""
+ counter = 0
+ listSize = len(last)
+ for n in range(0,nbParams):
+ if n+1 != nbParam:
+ if counter < listSize:
+ strResult = strResult + last[counter]
+ else:
+ strResult = strResult + ""
else:
- result = arg
-
- isEmpty = True
- paramsList = []
- if len(params) > 0:
- paramsList = params.split(":")
- isEmpty = False
-
- for n in range(1,nbParams+1):
- if n != nbParam and not isEmpty and len(paramsList[n-1])> 0:
- strResult = paramsList[n-1] + ":"
- pass
- if isVar and n == nbParam:
- if len(strResult) == 0 and nbParam != 1:
- strResult = strResult + ":"
- pass
- strResult = strResult+arg
- if n != nbParams:
- strResult = strResult + ":"
-
- return result, strResult
-
-
-#Wrapper class for StdMeshers_LocalLength hypothesis
-class LocalLength(BaseWrapper):
- def __init__(self, hypo):
- self.hypo = hypo
-
+ if isinstance(value, str) and notebook.isVariable(value):
+ result = notebook.get(value)
+ strResult=strResult+value
+ else:
+ strResult=strResult+str(value)
+ result = value
+ if nbParams - 1 != counter:
+ strResult=strResult+variable_separator #":"
+ counter = counter+1
+ return result, strResult
+
+class LocalLength(StdMeshers._objref_StdMeshers_LocalLength):
+
def SetLength(self, length):
- length,parameters = self.ParseParameters(self.hypo.GetParameters(),2,1,length)
- self.hypo.SetParameters(parameters)
- self.hypo.SetLength(length)
+ length,parameters = ParseParameters(StdMeshers._objref_StdMeshers_LocalLength.GetLastParameters(self),2,1,length)
+ StdMeshers._objref_StdMeshers_LocalLength.SetParameters(self,parameters)
+ StdMeshers._objref_StdMeshers_LocalLength.SetLength(self,length)
def SetPrecision(self, precision):
- precision,parameters = self.ParseParameters(self.hypo.GetParameters(),2,2,precision)
- self.hypo.SetParameters(parameters)
- self.hypo.SetPrecision(precision)
-
- def GetLength(self):
- return self.hypo.GetLength()
+ precision,parameters = ParseParameters(StdMeshers._objref_StdMeshers_LocalLength.GetLastParameters(self),2,2,precision)
+ StdMeshers._objref_StdMeshers_LocalLength.SetParameters(self,parameters)
+ StdMeshers._objref_StdMeshers_LocalLength.SetPrecision(self, precision)
- def GetPrecision(self):
- return self.hypo.GetLength()
+#Registering the new proxy for LocalLength
+omniORB.registerObjref(StdMeshers._objref_StdMeshers_LocalLength._NP_RepositoryId, LocalLength)
{
StdMeshers::StdMeshers_LocalLength_var h =
StdMeshers::StdMeshers_LocalLength::_narrow( hypothesis() );
- if(!aVariablesList.isEmpty()) {
- QString aVariables = aVariablesList.join(":");
- h->SetParameters(aVariables.toLatin1().constData());
- }
- else
- h->SetParameters("");
-
+
h->SetLength( params[0].myValue.toDouble() );
+ h->SetParameters(SMESHGUI::JoinObjectParameters(aVariablesList));
h->SetPrecision( params[1].myValue.toDouble() );
+ h->SetParameters(SMESHGUI::JoinObjectParameters(aVariablesList));
}
else if( hypType()=="SegmentLengthAroundVertex" )
{
{
StdMeshers::StdMeshers_LocalLength_var h =
StdMeshers::StdMeshers_LocalLength::_narrow( hyp );
-
- QString aParameters(h->GetParameters());
- QStringList aParametersList;
- if(aParameters.length())
- aParametersList = aParameters.split(":");
-
+ SMESH::ListOfParameters_var aParameters = hyp->GetLastParameters();
+
item.myName = tr("SMESH_LOCAL_LENGTH_PARAM");
- QVariant aVariable = parseParameter(aParametersList,0);
- if(aVariable.type() != QVariant::Invalid) {
- item.myValue = aVariable;
- item.isVariable = true;
- }
+
+ QString aVaribaleName = (aParameters->length() > 0) ? QString(aParameters[0].in()) : QString("");
+ item.isVariable = !aVaribaleName.isEmpty();
+ if(item.isVariable)
+ item.myValue = aVaribaleName;
else
item.myValue = h->GetLength();
p.append( item );
item.myName = tr("SMESH_LOCAL_LENGTH_PRECISION");
- aVariable = parseParameter(aParametersList,1);
- if(aVariable.type() != QVariant::Invalid) {
- item.myValue = aVariable;
- item.isVariable = true;
- }
+ aVaribaleName = (aParameters->length() > 1) ? QString(aParameters[1].in()) : QString("");
+ item.isVariable = !aVaribaleName.isEmpty();
+ if(item.isVariable)
+ item.myValue = aVaribaleName;
else
item.myValue = h->GetPrecision();
p.append( item );
* \brief
*/
//================================================================================
-QVariant StdMeshersGUI_StdHypothesisCreator::
+/*QVariant StdMeshersGUI_StdHypothesisCreator::
parseParameter(const QStringList& theList, int theNbParam) const
{
_PTR(Study) aStudy = SMESH::GetActiveStudyDocument();
}
return aResult;
}
+*/
virtual QWidget* getWidgetForParam( int paramIndex ) const;
virtual ListOfWidgets* customWidgets() const;
virtual void onReject();
- virtual QVariant parseParameter(const QStringList& theList, int theNbParam) const;
+ // virtual QVariant parseParameter(const QStringList& theList, int theNbParam) const;
template<class T>
T* widget(int i) const {