Index: cpp/frams/param/paramobj.cpp
===================================================================
--- cpp/frams/param/paramobj.cpp	(revision 286)
+++ cpp/frams/param/paramobj.cpp	(revision 326)
@@ -7,159 +7,215 @@
 #include <common/nonstd_stl.h>
 
-static const char* maybedup(bool dup,const char* src)
-{ return dup ? (src?strdup(src):0) : src; }
+static const char* maybedup(bool dup, const char* src)
+{
+	return dup ? (src ? strdup(src) : 0) : src;
+}
 static void maybefree(void* mem)
-{ if (mem) free(mem); }
-
-ParamEntry* ParamObject::makeParamTab(ParamInterface *pi,bool stripgroups,bool stripproc,
-				      int firstprop, int maxprops, bool dupentries, int flagsexclude)
-{
-ParamEntry *tab,*t;
-int i,n,offs;
-static ExtValue ex;
-int count=0,gcount=1;
-if (!stripgroups) gcount=pi->getGroupCount();
-if (stripproc||flagsexclude)
-for (int i=firstprop;i < pi->getPropCount();i++)
-	{
-	const char*t=pi->type(i);
-	if ((!stripproc)||(strchr("dfsox",*t)))
-		if ((!flagsexclude)||(!(pi->flags(i)&flagsexclude)))
-			if (++count >= maxprops) break;
-	}
-else count=pi->getPropCount()-firstprop;
-t=tab=(ParamEntry*)malloc(sizeof(ParamEntry)*(count+gcount+1));
-t->group=(short)gcount;
-t->flags=(short)count;
-t->name=maybedup(dupentries,pi->getName());
-t->type=maybedup(dupentries,pi->getDescription());
-for(i=0;i<gcount;i++)
-	{
-	t->id=maybedup(dupentries,pi->grname(i));
-	t->offset=0;
-	t++;
-	}
-n=1; offs=1;
-for (i=firstprop;i < pi->getPropCount();i++)
-	{
-	if ((!stripproc)||(strchr("dfsox",*pi->type(i))))
+{
+	if (mem) free(mem);
+}
+
+int ParamObject::firstFieldOffset()
+{
+	static ParamObject dummy(0, NULL);
+	return ((char*)&dummy.fields[0]) - (char*)&dummy;
+}
+
+ParamEntry* ParamObject::makeParamTab(ParamInterface *pi, bool stripgroups, bool stripproc,
+	int firstprop, int maxprops, bool dupentries, int flagsexclude, bool addnew, const char* rename)
+{
+	ParamEntry *tab, *t;
+	int i, n, offset;
+	static ExtValue ex;
+	int count = 0, gcount = 1;
+	if (!stripgroups) gcount = pi->getGroupCount();
+	if (stripproc || flagsexclude)
+		for (int i = firstprop; i < pi->getPropCount(); i++)
 		{
-		if ((!flagsexclude)||(!(pi->flags(i)&flagsexclude)))
+		const char*t = pi->type(i);
+		if ((!stripproc) || (strchr("dfsox", *t)))
+			if ((!flagsexclude) || (!(pi->flags(i)&flagsexclude)))
+				if (++count >= maxprops) break;
+		}
+	else count = pi->getPropCount() - firstprop;
+	if (addnew) count++;
+	t = tab = (ParamEntry*)malloc(sizeof(ParamEntry)*(count + gcount + 1));
+	t->group = (short)gcount;
+	t->flags = (short)count;
+	t->name = maybedup(dupentries, rename ? rename : pi->getName());
+	t->type = maybedup(dupentries, pi->getDescription());
+	for (i = 0; i < gcount; i++)
+	{
+		t->id = maybedup(dupentries, pi->grname(i));
+		t->offset = 0;
+		t++;
+	}
+	n = 1;
+	offset = firstFieldOffset();
+	if (addnew)
+	{
+		t->id = maybedup(dupentries, "new");
+		t->name = maybedup(dupentries, "create new object");
+		SString tmp = SString::sprintf("p o%s()", pi->getName());
+		t->type = maybedup(dupentries, (const char*)tmp);
+		t->help = maybedup(dupentries, pi->help(i));
+		t->flags = 0;
+		t->group = 0;
+		t->offset = PARAM_ILLEGAL_OFFSET;
+		t->fun1 = (void*)p_new;
+		t->fun2 = 0;
+		t++;
+	}
+	for (i = firstprop; i < pi->getPropCount(); i++)
+	{
+		if ((!stripproc) || (strchr("dfsox", *pi->type(i))))
+		{
+			if ((!flagsexclude) || (!(pi->flags(i)&flagsexclude)))
 			{
-			t->offset=offs*sizeof(ExtValue);
-			if (*pi->type(i)!='x') t->offset+=(((char*)&ex.data[0])-((char*)&ex));
-			t->group=(short)(stripgroups?0:pi->group(i));
-			t->flags=(short)pi->flags(i);
-			t->fun1=0;
-			t->fun2=0;
-			t->id=maybedup(dupentries,pi->id(i));
-			t->name=maybedup(dupentries,pi->name(i));
-			t->type=maybedup(dupentries,pi->type(i));
-			t->help=maybedup(dupentries,pi->help(i));
-			t++; n++; offs++;
-			if (n>count) break;
+				t->offset = offset;
+				if (*pi->type(i) != 'x') t->offset += (((char*)&ex.data[0]) - ((char*)&ex));
+				t->group = (short)(stripgroups ? 0 : pi->group(i));
+				t->flags = (short)pi->flags(i);
+				t->fun1 = 0;
+				t->fun2 = 0;
+				t->id = maybedup(dupentries, pi->id(i));
+				t->name = maybedup(dupentries, pi->name(i));
+				t->type = maybedup(dupentries, pi->type(i));
+				t->help = maybedup(dupentries, pi->help(i));
+				t++; n++; offset += sizeof(ExtValue);
+				if (n > count) break;
 			}
 		}
 	}
-t->id=0; t->group=0; t->flags=dupentries?MUTPARAM_ALLOCENTRY:0;
-return tab;
+	t->id = 0; t->group = 0; t->flags = dupentries ? MUTPARAM_ALLOCENTRY : 0;
+	return tab;
+}
+
+void ParamObject::setParamTabText(ParamEntry *pe, const char* &ptr, const char* txt)
+{
+	if (!paramTabAllocatedString(pe))
+		return;
+	maybefree((char*)ptr);
+	ptr = maybedup(true, txt);
+}
+
+bool ParamObject::paramTabAllocatedString(ParamEntry *pe)
+{
+	return (pe[pe->flags + pe->group].flags & MUTPARAM_ALLOCENTRY) ? true : false;
 }
 
 void ParamObject::freeParamTab(ParamEntry *pe)
 {
-if (pe[pe->flags+pe->group].flags & MUTPARAM_ALLOCENTRY)
-	{
-	int i;
-	ParamEntry *e;
-	maybefree((void*)pe->name);
-	maybefree((void*)pe->type);
-	for (i=0,e=pe;i<pe->group;i++,e++) 
-		maybefree((void*)e->id);
-	for (i=pe->group,e=pe+i;i<pe->group+pe->flags;i++,e++) 
+	if (paramTabAllocatedString(pe))
+	{
+		int i;
+		ParamEntry *e;
+		maybefree((void*)pe->name);
+		maybefree((void*)pe->type);
+		for (i = 0, e = pe; i < pe->group; i++, e++)
+			maybefree((void*)e->id);
+		for (i = pe->group, e = pe + i; i < pe->group + pe->flags; i++, e++)
 		{
-		maybefree((void*)e->id);
-		maybefree((void*)e->name);
-		maybefree((void*)e->type);
-		maybefree((void*)e->help);
+			maybefree((void*)e->id);
+			maybefree((void*)e->name);
+			maybefree((void*)e->type);
+			maybefree((void*)e->help);
 		}
 	}
-free(pe);
-}
-
-bool ParamObject::paramTabEqual(ParamEntry *pe1,ParamEntry *pe2)
-{
-if (pe1->flags != pe2->flags) return false;
-ParamEntry *e1=pe1+pe1->group, *e2=pe2+pe2->group;
-for(int i=0;i<pe1->flags;i++,e1++,e2++)
-	{
-	if (strcmp(e1->id,e2->id)) return false;
-	if (strcmp(e1->name,e2->name)) return false;
-	if (strcmp(e1->type,e2->type)) return false;
-	if (e1->offset!=e2->offset) return false;
-	}
-return true;
-}
-
-void* ParamObject::makeObject(ParamEntry *tab)
-{
-if (!tab) return 0;
-int n=tab->flags;
-if (!n) return 0;
-ExtValue *ret=new ExtValue[n+1];
-ret->setInt(n);
-ExtValue *v=ret+1;
-tab+=tab->group;
-for (;n>0;n--,v++,tab++)
-	switch(*tab->type)
-	{
-	case 'd': v->setInt(0); break;
-	case 'f': v->setDouble(0); break;
-	case 's': v->setString(SString::empty()); break;
-	case 'o': v->setObject(ExtObject()); break;
-	case 'x': break;
-	}
-return ret;
-}
-
-void ParamObject::copyObject(void* dst,void* src)
-{
-if ((!dst)||(!src)) return;
-ExtValue *s=(ExtValue *)src;
-ExtValue *d=(ExtValue *)dst;
-int n=min(s->getInt(),d->getInt());
-s++; d++;
-for (int i=0;i<n;i++,d++,s++)
-	*d=*s;
+	free(pe);
+}
+
+bool ParamObject::paramTabEqual(ParamEntry *pe1, ParamEntry *pe2)
+{
+	if (pe1->flags != pe2->flags) return false;
+	ParamEntry *e1 = pe1 + pe1->group, *e2 = pe2 + pe2->group;
+	for (int i = 0; i < pe1->flags; i++, e1++, e2++)
+	{
+		if (strcmp(e1->id, e2->id)) return false;
+		if (strcmp(e1->name, e2->name)) return false;
+		if (strcmp(e1->type, e2->type)) return false;
+		if (e1->offset != e2->offset) return false;
+	}
+	return true;
+}
+
+void ParamObject::p_new(void* obj, ExtValue *args, ExtValue *ret)
+{
+	ParamObject *this_obj = (ParamObject*)obj;
+	ParamObject *po = makeObject(this_obj->par.getParamTab());
+	ret->setObject(ExtObject(&this_obj->par, po));
+	po->par.setDefault();
+}
+
+ParamObject::ParamObject(int _numfields, ParamEntry *_tab)
+{
+	numfields = _numfields;
+	par.setParamTab(_tab);
+	par.select(this);
+	for (int i = 0; i < numfields; i++)
+		new(&fields[i])ExtValue();
+}
+
+ParamObject::~ParamObject()
+{
+	for (int i = 0; i < numfields; i++)
+		fields[i].~ExtValue();
+}
+
+ParamObject* ParamObject::makeObject(ParamEntry *tab)
+{
+	if (!tab) return 0;
+	int n = tab->flags;
+	if (!n) return 0;
+	ParamObject *obj = new(n)ParamObject(n, tab); // new(n): allocate n fields ; ParamObject(n,...): tell the object it has n fields
+	ExtValue *v = &obj->fields[0];
+	tab += tab->group;
+	for (; n > 0; n--, tab++)
+		switch (*tab->type)
+	{
+		case 'd': v->setInt(0); v++; break;
+		case 'f': v->setDouble(0); v++; break;
+		case 's': v->setString(SString::empty()); v++; break;
+		case 'o': v->setObject(ExtObject()); v++; break;
+		case 'x': v++; break;
+	}
+	return obj;
+}
+
+void ParamObject::operator=(const ParamObject& src)
+{
+	const ExtValue *s = &src.fields[0];
+	ExtValue *d = &fields[0];
+	int n = min(numfields, src.numfields);
+	for (int i = 0; i < n; i++, d++, s++)
+		*d = *s;
+}
+
+ParamObject* ParamObject::clone()
+{
+	ParamObject *c = new(numfields)ParamObject(numfields, par.getParamTab());
+	*c = *this;
+	return c;
+}
+
+void ParamObject::copyObject(void* dst, void* src)
+{
+	if ((!dst) || (!src)) return;
+	ParamObject *s = (ParamObject*)src;
+	ParamObject *d = (ParamObject*)dst;
+	*d = *s;
 }
 
 void* ParamObject::dupObject(void* src)
 {
-if (!src) return NULL;
-ExtValue *s=(ExtValue *)src;
-int n=s->getInt();
-
-ExtValue *ret=new ExtValue[n+1];
-ExtValue *d=ret;
-d->setInt(n);
-d++; s++;
-
-for (int i=0;i<n;i++,d++,s++)
-	*d=*s;
-
-return ret;
+	if (!src) return NULL;
+	ParamObject *s = (ParamObject*)src;
+	return s->clone();
 }
 
 void ParamObject::freeObject(void* obj)
 {
-if (!obj) return;
-delete[] (ExtValue *)obj;
-}
-
-
-
-
-
-
-
-
-
+	if (!obj) return;
+	ParamObject *o = (ParamObject*)obj;
+	delete o;
+}
