Index: cpp/frams/param/mutableparam.cpp
===================================================================
--- cpp/frams/param/mutableparam.cpp	(revision 138)
+++ cpp/frams/param/mutableparam.cpp	(revision 138)
@@ -0,0 +1,291 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "mutableparam.h"
+#include <frams/util/extvalue.h>
+
+#define FIELDSTRUCT MutableParam
+ParamEntry MutableParam::pe_tab[]=
+{
+{"clear",0,PARAM_DONTSAVE+PARAM_USERHIDDEN,"remove all properties","p",PROCEDURE(p_clear),},
+{"add",0,PARAM_DONTSAVE+PARAM_USERHIDDEN,"add property (id,type,name,help)","p",PROCEDURE(p_addprop),},
+{"remove",0,PARAM_DONTSAVE+PARAM_USERHIDDEN,"remove property (index)","p",PROCEDURE(p_remprop),},
+{"addGroup",0,PARAM_DONTSAVE+PARAM_USERHIDDEN,"add group (name)","p",PROCEDURE(p_addgroup),},
+{"removeGroup",0,PARAM_DONTSAVE+PARAM_USERHIDDEN,"remove group (index)","p",PROCEDURE(p_remgroup),},
+{"changedProperty",0,PARAM_DONTSAVE+PARAM_USERHIDDEN+PARAM_READONLY,"last changed property #","d",FIELD(changed),},
+{"changedPropertyId",0,PARAM_DONTSAVE+PARAM_USERHIDDEN+PARAM_READONLY,"last changed property id","s",GETONLY(changedname),},
+};
+#undef FIELDSTRUCT
+
+MutableParam::MutableParam(const char*n,const char*g,int gr0)
+	:SimpleAbstractParam(this,n),persistgroup0(gr0),grprefix(g)
+{
+if (persistgroup0)
+	addGroup(grprefix,1);
+}
+
+int MutableParam::findGroup(const SString name,int ignoreprefix)
+{
+int skipprefix=grprefix.len()?grprefix.len()+2:0;
+for (int i=0;i<groups.size();i++)
+	{
+	if (ignoreprefix)
+		{
+      const char *noprefix=(const char*)groupname(i);
+      if ((int)strlen(noprefix) < skipprefix) continue;
+		noprefix+=skipprefix;
+		if (!strcmp(noprefix,(const char*)name)) return i;
+		}
+		else
+			if (groupname(i)==name) return i;
+	}
+return -1;
+}
+
+int MutableParam::addGroup(const SString& gname,int noprefix)
+{
+SString tmp;
+if (noprefix)
+	tmp=gname;
+else
+	{
+	tmp=grprefix;
+	if (tmp.len()) tmp+=": ";
+	tmp+=gname;
+	}
+groups+=new SString(tmp);
+int position=groups.size()-1;
+ongroupadd.action(position);
+return position;
+}
+
+void MutableParam::removeGroup(int g)
+{
+if ((g<0)||(g>=MutableParam::getGroupCount())) return;
+ParamEntry *e;
+for (int i=MutableParam::getPropCount()-1;i>=staticprops;i--)
+	{
+	e=entry(i);
+	if (g==e->group)
+		removeProperty(i);
+	}
+SString *s=(SString *)groups(g);
+if (s) delete s;
+groups-=g;
+ongroupdelete.action(g);
+}
+
+int MutableParam::grmember(int g,int a)
+{
+if (g==0)
+	{
+	if (getGroupCount()<2)
+		return (a<getPropCount())?a:-9999;
+	if (a<staticprops) return a;
+	a-=staticprops;
+	}
+ParamEntry *e;
+for (int i=staticprops;e=entry(i);i++)
+	if (g==e->group)
+		if (!a--) return i;
+return -9999;
+}
+
+int MutableParam::addProperty(ParamEntry *pe,int position)
+{
+DB(printf("MutableParam::add(%s)\n",pe->id));
+if (position<0)
+	position=entries.size()+staticprops;
+entries.insert(position-staticprops,pe);
+
+if (pe->offset)
+	pe->flags &= ~MUTPARAM_ALLOCDATA;
+else
+	{
+	pe->flags |= MUTPARAM_ALLOCDATA;
+	void *d=0;
+	switch(pe->type[0])
+		{
+		case 'd': d=new int(); *((int*)d)=0; break;
+		case 'f': d=new double(); *((double*)d)=0; break;
+		case 's': d=new SString(); break;
+		case 'x': d=new ExtValue(); break;
+		case 'o': d=new ExtObject(); break;
+		}
+	pe->offset=(int)d;
+	}
+onadd.action(position);
+return position;
+}
+
+ParamEntry * MutableParam::removeProperty(ParamEntry *pe)
+{
+   int index=entries.find(pe);
+   if (index>=0) return removeProperty(index); else return pe;
+}
+
+ParamEntry * MutableParam::removeProperty(int i)
+{
+ParamEntry *pe=(ParamEntry *)entries(i-staticprops);
+DB(printf("MutableParam::remove(%d)\n",i));
+void *d=(void*)pe->offset;
+if (d && (pe->flags & MUTPARAM_ALLOCDATA))
+	switch(pe->type[0])
+		{
+		case 'd': delete (int*)d; break;
+		case 'f': delete (double*)d; break;
+		case 's': delete (SString*)d; break;
+		case 'x': delete (ExtValue*)d; break;
+		case 'o': delete (ExtObject*)d; break;
+		}
+entries-=i-staticprops;
+if (pe->flags & MUTPARAM_ALLOCENTRY)
+	{
+	if (pe->name) free((void*)pe->name);
+	if (pe->id) free((void*)pe->id);
+	if (pe->help) free((void*)pe->help);
+	if (pe->type) free((void*)pe->type);
+	delete pe;
+	}
+ondelete.action(i);
+return pe;
+}
+
+void MutableParam::clear(int everything)
+{
+DB(printf("MutableParam::clear\n"));
+for (int i=entries.size()-1;i>=0;i--)
+	removeProperty(i+staticprops);
+int lastgroup=(everything || (persistgroup0==0))?0:1;
+for (int i=groups.size()-1;i>=lastgroup;i--)
+	removeGroup(i);
+}
+
+void MutableParam::p_clear(ExtValue *args,ExtValue *ret)
+{ clear(); }
+
+int MutableParam::addProperty(void* data,const char* id,const char* type,const char* name,const char* help,int flags,int group,int position)
+{
+if ((!id)&&(!type)) return -1;
+ParamEntry *pe=new ParamEntry();
+pe->fun1=0; pe->fun2=0;
+pe->group=(short)group;
+pe->flags=(short)(flags | MUTPARAM_ALLOCENTRY);
+pe->offset=(long)data;
+pe->id=strdup(id);
+pe->type=strdup(type);
+pe->name=name?strdup(name):0;
+pe->help=help?strdup(help):0;
+return addProperty(pe,position);
+}
+
+void MutableParam::p_addprop(ExtValue *args,ExtValue *ret)
+{
+int i=addProperty(0,args[2].getString(),args[1].getString(),args[0].getString());
+ret->setInt(i);
+}
+
+void MutableParam::p_remprop(ExtValue *args,ExtValue *ret)
+{
+removeProperty(args[0].getInt());
+}
+
+void MutableParam::p_addgroup(ExtValue *args,ExtValue *ret)
+{
+int i=addGroup(args[0].getString());
+ret->setInt(i);
+}
+
+void MutableParam::p_remgroup(ExtValue *args,ExtValue *ret)
+{
+removeGroup(args[0].getInt());
+}
+
+void MutableParam::notify(int id)
+{
+changed=id;
+onactivate.action(id);
+}
+
+int MutableParam::setInt(int i,long v)
+{
+int ret=SimpleAbstractParam::setInt(i,v);
+if (ret & PSET_CHANGED) notify(i);
+return ret;
+}
+
+int MutableParam::setDouble(int i,double v)
+{
+int ret=SimpleAbstractParam::setDouble(i,v);
+if (ret & PSET_CHANGED) notify(i);
+return ret;
+}
+
+int MutableParam::setString(int i,const SString &v)
+{
+int ret=SimpleAbstractParam::setString(i,v);
+if (ret & PSET_CHANGED) notify(i);
+return ret;
+}
+
+int MutableParam::setObject(int i,const ExtObject &v)
+{
+int ret=SimpleAbstractParam::setObject(i,v);
+if (ret & PSET_CHANGED) notify(i);
+return ret;
+}
+
+int MutableParam::setExtValue(int i,const ExtValue &v)
+{
+int ret=SimpleAbstractParam::setExtValue(i,v);
+if (ret & PSET_CHANGED) notify(i);
+return ret;
+}
+
+void MutableParam::call(int i,ExtValue* args,ExtValue *ret)
+{
+if (i<staticprops) return SimpleAbstractParam::call(i,args,ret);
+notify(i);
+}
+
+///////////////////
+
+void ParamSaver::clear()
+{
+for(int i=0;i<store.size();i+=2)
+	{
+	SString *n=(SString*)store(i);
+	ExtValue *v=(ExtValue*)store(i+1);
+	delete n;
+	delete v;
+	}	
+store.clear();
+}
+
+void ParamSaver::loadFrom(ParamInterface& p)
+{
+int N=p.getPropCount();
+for(int i=0;i<N;i++)
+	{
+	if (shouldLoad(p,i))
+		{
+		ExtValue v;
+		p.get(i,v);
+		store+=new SString(p.id(i));
+		store+=new ExtValue(v);
+		}
+	}
+}
+
+void ParamSaver::saveTo(MutableParam& p)
+{
+for(int i=0;i<store.size();i+=2)
+	{
+	SString *n=(SString*)store(i);
+	int prop=p.findId((const char*)*n);
+	if (prop<0)
+		prop=p.addProperty(0,(const char*)*n,"x",0,0,0,0,-1);
+	p.setExtValue(prop,*(ExtValue*)store(i+1));
+	}
+}
Index: cpp/frams/param/mutableparam.h
===================================================================
--- cpp/frams/param/mutableparam.h	(revision 138)
+++ cpp/frams/param/mutableparam.h	(revision 138)
@@ -0,0 +1,86 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _MUTABLEPARAM_H_
+#define _MUTABLEPARAM_H_
+
+#include "mutparamiface.h"
+#include <frams/util/extvalue.h>
+#include "param.h"
+#include <frams/util/callbacks.h>
+
+class VMachine;
+class VMCode;
+
+class MutableParam: public SimpleAbstractParam, public MutableParamInterface 
+{
+static const int staticprops=7;
+static ParamEntry pe_tab[];
+/** group #0 cannot be removed by scripting  */
+int persistgroup0;
+SString grprefix;
+SList entries;
+SList groups;
+long changed;
+ParamEntry *entry(int i) {return (i<staticprops)? pe_tab+i : ((ParamEntry*)entries(i-staticprops));}
+void *getTarget(int i) {return (i<staticprops)? SimpleAbstractParam::getTarget(i) : (void*)entry(i)->offset;}
+void call(int i,ExtValue* args,ExtValue *ret);
+  public:
+void clear(int everything=0);
+int firstMutableIndex() {return staticprops;}
+SString& groupname(int g) {return *((SString*)groups(g));}
+MutableParam(const char*n=0,const char*g=0,int gr0=1);
+void setGroupName(const SString &n,int g=0) {groupname(g)=n;}
+~MutableParam() {clear(1);}
+int getGroupCount() {return groups.size();}
+int getPropCount() {return entries.size()+staticprops;}
+const char *grname(int i) {return (i>=groups.size()) ? 0 : (const char*)groupname(i);}
+int grmember(int g,int a);
+
+int addGroup(const SString& gname,int noprefix=0);
+void removeGroup(int pos);
+
+int findGroup(const SString name,int ignoreprefix=0);
+
+/** @param data pointer to the variable. 0 will allocate new variable
+    @param position -1 = after the last one  */
+int addProperty(void* data,const char* id,const char* type,const char* name,const char* help=0,int flags=0,int group=0,int position=-1);
+
+int addProperty(ParamEntry *pe,int position=-1);
+ParamEntry * removeProperty(ParamEntry *pe);
+ParamEntry * removeProperty(int i);
+
+void notify(int id);
+
+int setInt(int,long);
+int setDouble(int,double);
+int setString(int,const SString &);
+int setObject(int,const ExtObject &);
+int setExtValue(int,const ExtValue &);
+
+#define STATRICKCLASS MutableParam
+PARAMPROCDEF(p_clear);
+PARAMPROCDEF(p_addprop);
+PARAMPROCDEF(p_remprop);
+PARAMPROCDEF(p_addgroup);
+PARAMPROCDEF(p_remgroup);
+PARAMGETDEF(changedname) {arg1->setString(id(changed));}
+#undef STATRICKCLASS
+};
+
+class ParamSaver
+{
+SList store;
+  public:
+virtual bool shouldLoad(ParamInterface &pi,int i) {return true;}
+ParamSaver() {}
+ParamSaver(ParamInterface &pi) {loadFrom(pi);}
+~ParamSaver() {clear();}
+void loadFrom(ParamInterface& p);
+void saveTo(MutableParam& p);
+void clear();
+};
+
+
+#endif
Index: cpp/frams/param/mutparamiface.h
===================================================================
--- cpp/frams/param/mutparamiface.h	(revision 138)
+++ cpp/frams/param/mutparamiface.h	(revision 138)
@@ -0,0 +1,23 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _MUTPARAM_H_
+#define _MUTPARAM_H_
+
+#include <frams/util/callbacks.h>
+#include "param.h"
+
+class MutableParamInterface: public virtual ParamInterface
+{
+public:
+Callback onadd;
+Callback ondelete;
+Callback onchange;
+Callback ongroupadd;
+Callback ongroupdelete;
+Callback ongroupchange;
+Callback onactivate;
+};
+
+#endif
Index: cpp/frams/param/mutparamlist.cpp
===================================================================
--- cpp/frams/param/mutparamlist.cpp	(revision 138)
+++ cpp/frams/param/mutparamlist.cpp	(revision 138)
@@ -0,0 +1,366 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#include "mutparamlist.h"
+#include <frams/util/extvalue.h>
+
+struct ParamInfo
+{
+ParamInterface *pi;
+MutableParamInterface *mpi;
+CallbackNode *anode,*dnode,*ganode,*gdnode,*cnode,*gcnode,*panode;
+int firstprop, firstgroup;
+int propcount, groupcount;
+};
+
+ParamInfo* MutableParamList::getParamInfo(int i)
+{
+return (ParamInfo*)list(i);
+}
+
+void MutableParamList::addPI(int pos,ParamInfo *pi)
+{
+int propcount=pi->propcount;
+int groupcount=pi->groupcount;
+if (pos==0)
+	{ pi->firstprop=0; pi->firstgroup=0; }
+else
+	{
+	ParamInfo *prev_pi=getParamInfo(pos-1);
+	pi->firstprop=prev_pi->firstprop+prev_pi->propcount;
+	pi->firstgroup=prev_pi->firstgroup+prev_pi->groupcount;
+	}
+list.insert(pos,pi);
+pi->propcount=0;
+pi->groupcount=0;
+for (int i=0;i<groupcount;i++)
+	{
+	pi->groupcount=i+1;
+	adjustPI(pos+1,0,1);
+	ongroupadd.action(pi->firstgroup+i);
+	}
+for (int i=0;i<propcount;i++)
+	{
+	pi->propcount=i+1;
+	adjustPI(pos+1,1,0);
+	onadd.action(pi->firstprop+i);
+	}
+if (pi->mpi)
+	{
+	pi->anode=pi->mpi->onadd.add(STATRICKCALLBACK(this,&MutableParamList::onPropAdd,pi));
+	pi->ganode=pi->mpi->ongroupadd.add(STATRICKCALLBACK(this,&MutableParamList::onGroupAdd,pi));
+	pi->dnode=pi->mpi->ondelete.add(STATRICKCALLBACK(this,&MutableParamList::onPropDelete,pi));
+	pi->gdnode=pi->mpi->ongroupdelete.add(STATRICKCALLBACK(this,&MutableParamList::onGroupDelete,pi));
+	pi->cnode=pi->mpi->onchange.add(STATRICKCALLBACK(this,&MutableParamList::onPropChange,pi));
+	pi->gcnode=pi->mpi->ongroupchange.add(STATRICKCALLBACK(this,&MutableParamList::onGroupChange,pi));
+	pi->panode=pi->mpi->onactivate.add(STATRICKCALLBACK(this,&MutableParamList::onPropActivate,pi));
+	}
+}
+
+int MutableParamList::findPI(ParamInfo *pi)
+{
+return list.find((void*)pi);
+}
+
+int MutableParamList::findPI(ParamInterface *p)
+{
+ParamInfo *pi;
+for(int i=0;pi=(ParamInfo*)list(i);i++)
+	if ((!pi->mpi)&&(pi->pi==p)) return i;
+return -1;
+}
+
+int MutableParamList::findPI(MutableParamInterface *p)
+{
+ParamInfo *pi;
+for(int i=0;pi=(ParamInfo*)list(i);i++)
+	if ((pi->mpi)&&(pi->mpi==p)) return i;
+return -1;
+}
+
+void MutableParamList::adjustPI(int firstPI,int addprop,int addgroup)
+{
+ParamInfo *pi;
+for (int i=firstPI;pi=getParamInfo(i);i++)
+	{
+	pi->firstprop+=addprop;
+	pi->firstgroup+=addgroup;
+	}
+}
+
+void MutableParamList::removePI(int pi_index)
+{
+if (pi_index<0) return;
+ParamInfo *pi=getParamInfo(pi_index);
+for (int i=pi->propcount-1;i>=0;i--)
+	{
+	pi->propcount=i;
+	adjustPI(pi_index+1,-1,0);
+	ondelete.action(i);
+	}
+for (int i=pi->groupcount-1;i>=0;i--)
+	{
+	pi->groupcount=i;
+	adjustPI(pi_index+1,0,-1);
+	ongroupdelete.action(i);
+	}
+list-=(pi_index);
+if (pi->mpi)
+	{
+	pi->mpi->onadd.remove(pi->anode);
+	pi->mpi->ongroupadd.remove(pi->ganode);
+	pi->mpi->ondelete.remove(pi->dnode);
+	pi->mpi->ongroupdelete.remove(pi->gdnode);
+	pi->mpi->onchange.remove(pi->cnode);
+	pi->mpi->ongroupchange.remove(pi->gcnode);
+	pi->mpi->onactivate.remove(pi->panode);
+	}
+delete pi;
+}
+
+MutableParamList::~MutableParamList()
+{
+for (int i=list.size()-1;i>=0;i--)
+	removePI(i);
+}
+
+void MutableParamList::onPropAdd(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+pi->propcount++;
+int j=findPI(pi);
+if (j>=0)
+	adjustPI(j+1,1,0);
+onadd.action(pi->firstprop+i);
+}
+
+void MutableParamList::onPropDelete(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+pi->propcount--;
+int j=findPI(pi);
+if (j>=0)
+	adjustPI(j+1,-1,0);
+ondelete.action(pi->firstprop+i);
+}
+
+void MutableParamList::onPropChange(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+onchange.action(pi->firstprop+i);
+}
+
+void MutableParamList::onPropActivate(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+onactivate.action(pi->firstprop+i);
+}
+
+void MutableParamList::onGroupAdd(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+pi->groupcount++;
+int j=findPI(pi);
+if (j>=0)
+	adjustPI(j+1,0,1);
+ongroupadd.action(pi->firstgroup+i);
+}
+
+void MutableParamList::onGroupDelete(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+pi->groupcount--;
+int j=findPI(pi);
+if (j>=0)
+	adjustPI(j+1,0,-1);
+ongroupdelete.action(pi->firstgroup+i);
+}
+
+void MutableParamList::onGroupChange(void* data,long i)
+{
+ParamInfo *pi=(ParamInfo*)data;
+ongroupchange.action(pi->firstgroup+i);
+}
+
+void MutableParamList::insert(int pos,MutableParamInterface *p)
+{
+ParamInfo *pi=new ParamInfo();
+pi->pi=(ParamInterface*)p;
+pi->mpi=p;
+pi->propcount=p->getPropCount();
+pi->groupcount=p->getGroupCount();
+addPI(pos,pi);
+}
+
+void MutableParamList::insert(int pos,ParamInterface *p)
+{
+ParamInfo *pi=new ParamInfo();
+pi->pi=p;
+pi->mpi=0;
+pi->propcount=p->getPropCount();
+pi->groupcount=p->getGroupCount();
+addPI(pos,pi);
+}
+
+
+void MutableParamList::operator+=(ParamInterface *p)
+{
+insert(list.size(),p);
+}
+
+void MutableParamList::operator+=(MutableParamInterface *p)
+{
+insert(list.size(),p);
+}
+
+
+void MutableParamList::operator-=(ParamInterface *p)
+{
+int i=findPI(p);
+removePI(i);
+}
+
+void MutableParamList::operator-=(MutableParamInterface *p)
+{
+int i=findPI(p);
+removePI(i);
+}
+
+void MutableParamList::operator-=(int i)
+{
+removePI(i);
+}
+
+int MutableParamList::getGroupCount()
+{
+int count=0;
+FOREACH(ParamInfo*,pi,list)
+	count+=pi->groupcount;
+return count;
+}
+
+int MutableParamList::getPropCount()
+{
+int count=0;
+FOREACH(ParamInfo*,pi,list)
+	count+=pi->propcount;
+return count;
+}
+
+int MutableParamList::getSubParam(int i,ParamInterface **sub_p,int *sub_i)
+{
+int n;
+FOREACH(ParamInfo*,pi,list)
+	{
+	if (i<(n=pi->propcount))
+		{
+		*sub_p=pi->pi;
+		*sub_i=i;
+		return 1;
+		}
+	i-=n;
+	}
+return 0;
+}
+
+int MutableParamList::getSubGroup(int i,ParamInterface **sub_p,int *sub_i)
+{
+int n;
+FOREACH(ParamInfo*,pi,list)
+	{
+	if (i<(n=pi->groupcount))
+		{
+		*sub_p=pi->pi;
+		*sub_i=i;
+		return 1;
+		}
+	i-=n;
+	}
+return 0;
+}
+
+#define FUN(_type_,_name_,_ret_) \
+_type_ MutableParamList:: _name_ (int i) \
+{ \
+int j; ParamInterface *pi; \
+if (!getSubParam(i,&pi,&j)) return _ret_; \
+return pi-> _name_ (j); \
+}
+
+FUN(const char*,id,0)
+FUN(const char*,name,0)
+FUN(const char*,type,0)
+FUN(const char*,help,0)
+FUN(int,flags,0)
+FUN(SString,getString,SString())
+FUN(long,getInt,0)
+FUN(double,getDouble,0)
+FUN(ExtValue,getExtValue,ExtValue((long)0))
+FUN(ExtObject,getObject,ExtObject())
+
+int MutableParamList::group(int i)
+{
+int n;
+int g=0;
+FOREACH(ParamInfo*,pi,list)
+	{
+	if (i<(n=pi->propcount))
+		return g + pi->pi->group(i);
+	g+=pi->groupcount;
+	i-=n;
+	}
+return 0;
+}
+
+#define FUN2(_type_,_name_,_argt_) \
+_type_ MutableParamList:: _name_ (int i,_argt_ v) \
+{ \
+int j; ParamInterface *pi; \
+if (!getSubParam(i,&pi,&j)) return 0; \
+return pi-> _name_ (j,v); \
+}
+
+FUN2(int,setInt,long)
+FUN2(int,setDouble,double)
+FUN2(int,setString,const SString &)
+FUN2(int,setObject,const ExtObject &)
+FUN2(int,setExtValue,const ExtValue &)
+
+void MutableParamList::call(int i,ExtValue* args,ExtValue *ret)
+{
+int j; ParamInterface *pi;
+if (!getSubParam(i,&pi,&j)) return;
+pi->call(j,args,ret);
+}
+
+const char *MutableParamList::grname(int i)
+{
+int j; ParamInterface *pi;
+if (!getSubGroup(i,&pi,&j)) return 0;
+return pi->grname(j);
+}
+
+int MutableParamList::grmember(int gi,int i)
+{
+int n;
+int count=0;
+FOREACH(ParamInfo*,pi,list)
+	{
+	if (gi<(n=pi->groupcount))
+		{
+		int prop=pi->pi->grmember(gi,i);
+		if (prop>=pi->propcount) return -9999;
+		return count+prop;
+		}
+	count+=pi->propcount;
+	gi-=n;
+	}
+return -9999;
+}
+
+void MutableParamList::clear()
+{
+for (int i=list.size()-1;i>=0;i--)
+	operator-=(i);
+}
Index: cpp/frams/param/mutparamlist.h
===================================================================
--- cpp/frams/param/mutparamlist.h	(revision 138)
+++ cpp/frams/param/mutparamlist.h	(revision 138)
@@ -0,0 +1,97 @@
+// This file is a part of the Framsticks GDK.
+// Copyright (C) 2002-2014  Maciej Komosinski and Szymon Ulatowski.  See LICENSE.txt for details.
+// Refer to http://www.framsticks.com/ for further information.
+
+#ifndef _MUTPARAMLIST_H_
+#define _MUTPARAMLIST_H_
+
+#include "param.h"
+#include "mutparamiface.h"
+#include <frams/util/list.h>
+
+struct ParamInfo;
+
+class MutableParamList: public virtual ParamInterface, public MutableParamInterface
+{
+SList list;
+const char *objname;
+int getSubParam(int i,ParamInterface **sub_p,int *sub_i);
+int getSubGroup(int i,ParamInterface **sub_p,int *sub_i);
+
+ParamInfo* getParamInfo(int i);
+void addPI(int pos,ParamInfo *pi);
+int findPI(ParamInfo *pi);
+int findPI(ParamInterface *p);
+int findPI(MutableParamInterface *p);
+void adjustPI(int firstPI,int addprop,int addgroup);
+void removePI(int pi_index);
+
+#define STATRICKCLASS MutableParamList
+STCALLBACKDEF(onPropAdd);
+STCALLBACKDEF(onPropDelete);
+STCALLBACKDEF(onGroupAdd);
+STCALLBACKDEF(onGroupDelete);
+STCALLBACKDEF(onPropChange);
+STCALLBACKDEF(onGroupChange);
+STCALLBACKDEF(onPropActivate);
+#undef STATRICKCLASS
+
+public:
+
+void firePropChange(int i) {onchange.action(i);}
+void fireGroupChange(int i) {ongroupchange.action(i);}
+
+MutableParamList(const char* n=0,const char* d=0):objname(n),description(d) {}
+~MutableParamList();
+
+void operator+=(ParamInterface *p);
+void operator-=(ParamInterface *p);
+void operator+=(MutableParamInterface *p);
+void operator-=(MutableParamInterface *p);
+void insert(int i,ParamInterface *p);
+void insert(int i,MutableParamInterface *p);
+void operator-=(int i);
+
+/** remove all sub params */
+void clear();
+
+const char* getName() {return objname;}
+const char* description;
+const char* getDescription() {return description;}
+
+int getGroupCount();
+int getPropCount();
+
+const char *id(int i);
+const char *name(int i);
+const char *type(int i);
+const char *help(int i);
+int flags(int i);
+int group(int i);
+void call(int i,ExtValue* args,ExtValue *ret);
+const char *grname(int i);
+
+int grmember(int gi,int n);
+
+SString getString(int);
+long getInt(int);
+double getDouble(int);
+ExtValue getExtValue(int);
+ExtObject getObject(int);
+
+int setInt(int,long);
+int setDouble(int,double);
+int setString(int,const SString &);
+int setObject(int,const ExtObject&);
+int setExtValue(int,const ExtValue&);
+};
+
+#endif
+
+
+
+
+
+
+
+
