Commit cad762a6 authored by thomas's avatar thomas
Browse files

PD: added TCL/TK attribute editor and file saving


git-svn-id: https://svn.grrrr.org/ext/trunk@669 4d9ac71a-51e6-0310-8455-cad1006bcd31
parent ff84071f
......@@ -15,6 +15,7 @@ Version history:
0.5.0:
- added some more SIMD functions
- PD attributes: added a TCL/TK editor dialog ("properties") and save attributes to patcher
- fixed wrong returned result of flext::buffer::set function
- fix for linux static exported function name-clash (individual linker namings for exported flext base classes)
- made message queue stuff global (static) for all flext objects
......
......@@ -1202,6 +1202,9 @@
BrowseInformation="1"/>
</FileConfiguration>
</File>
<File
RelativePath=".\source\flattr_ed.cpp">
</File>
<File
RelativePath="source\flbind.cpp">
<FileConfiguration
......
SRCS=flbase.cpp flext.cpp flbuf.cpp fldsp.cpp fllib.cpp flxlet.cpp flattr.cpp flsupport.cpp \
SRCS=flbase.cpp flext.cpp flbuf.cpp fldsp.cpp fllib.cpp flxlet.cpp flattr.cpp flattr_ed.cpp flsupport.cpp \
flutil.cpp flatom.cpp flatom_pr.cpp flthr.cpp fltimer.cpp flsimd.cpp flout.cpp \
flatom_app.cpp flatom_part.cpp flitem.cpp flmeth.cpp flmsg.cpp \
flproxy.cpp flqueue.cpp flbind.cpp
......
......@@ -156,7 +156,11 @@ bool flext_base::InitAttrib(int argc,const t_atom *argv)
if(IsString(argv[nxt]) && *GetString(argv[nxt]) == '@') break;
const t_symbol *tag = MakeSymbol(GetString(argv[cur])+1);
SetAttrib(tag,nxt-cur-1,argv+cur+1);
attritem *attr = FindAttrib(tag,false,true);
if(attr) {
if(SetAttrib(attr,nxt-cur-1,argv+cur+1))
SetAttribSave(attr,true);
}
}
return true;
}
......@@ -193,7 +197,7 @@ bool flext_base::cb_ListMethods(flext_base *c,int argc,const t_atom *argv)
return false;
}
flext_base::attritem *flext_base::FindAttr(const t_symbol *tag,bool get) const
flext_base::attritem *flext_base::FindAttrib(const t_symbol *tag,bool get,bool msg) const
{
// first search within object scope
attritem *a = (attritem *)attrhead->Find(tag);
......@@ -204,19 +208,22 @@ flext_base::attritem *flext_base::FindAttr(const t_symbol *tag,bool get) const
a = (attritem *)clattrhead->Find(tag);
while(a && (a->tag != tag || a->inlet != 0 || (get?a->IsSet():a->IsGet()))) a = (attritem *)a->nxt;
}
if(!a && msg) {
// print a message
error("%s - %s: attribute not found",thisName(),GetString(tag));
}
return a;
}
bool flext_base::SetAttrib(const t_symbol *tag,int argc,const t_atom *argv)
{
// search for matching attribute
attritem *a = FindAttr(tag,false);
attritem *a = FindAttrib(tag,false,true);
if(a)
return SetAttrib(a,argc,argv);
else {
error("%s - %s: attribute not found",thisName(),GetString(tag));
else
return true;
}
}
bool flext_base::SetAttrib(attritem *a,int argc,const t_atom *argv)
......@@ -323,13 +330,25 @@ bool flext_base::GetAttrib(attritem *a)
bool flext_base::GetAttrib(const t_symbol *s,AtomList &a) const
{
attritem *attr = FindAttr(s,true);
attritem *attr = FindAttrib(s,true);
return attr && GetAttrib(attr,a);
}
bool flext_base::DumpAttrib(const t_symbol *attr) const
{
attritem *item = FindAttr(attr,true);
attritem *item = FindAttrib(attr,true);
return item && const_cast<flext_base *>(this)->GetAttrib(item);
}
void flext_base::SetAttribSave(attritem *a,bool save)
{
a->SetSave(save);
if(a->BothExist()) {
// find opposite attribute item
attritem *b = FindAttrib(a->tag,!a->IsGet());
FLEXT_ASSERT(b != NULL);
b->SetSave(save);
}
}
/*
flext - C++ layer for Max/MSP and pd (pure data) externals
Copyright (c) 2001-2003 Thomas Grill (xovo@gmx.net)
For information on usage and redistribution, and for a DISCLAIMER OF ALL
WARRANTIES, see the file, "license.txt," in this distribution.
*/
/*! \file flattr_ed.cpp
\brief Attribute editor (property dialog) for PD
*/
#include "flprefix.h"
#if FLEXT_SYS == FLEXT_SYS_PD && !defined(FLEXT_NOATTREDIT)
#ifdef _MSC_VER
#pragma warning( disable : 4091 )
#endif
#include <m_imp.h>
#include "flext.h"
#include <string.h>
#include <stdio.h>
#ifdef __MWERKS__
#define STD std
#else
#define STD
#endif
#if !defined(PD_VERSION_MAJOR)
/* PD version 0.36 or below */
/* Call this to get a gobj's bounding rectangle in pixels */
typedef void (*t_getrectfn)(t_gobj *x, struct _glist *glist,
int *x1, int *y1, int *x2, int *y2);
/* and this to displace a gobj: */
typedef void (*t_displacefn)(t_gobj *x, struct _glist *glist, int dx, int dy);
/* change color to show selection: */
typedef void (*t_selectfn)(t_gobj *x, struct _glist *glist, int state);
/* change appearance to show activation/deactivation: */
typedef void (*t_activatefn)(t_gobj *x, struct _glist *glist, int state);
/* warn a gobj it's about to be deleted */
typedef void (*t_deletefn)(t_gobj *x, struct _glist *glist);
/* making visible or invisible */
typedef void (*t_visfn)(t_gobj *x, struct _glist *glist, int flag);
/* field a mouse click (when not in "edit" mode) */
typedef int (*t_clickfn)(t_gobj *x, struct _glist *glist,
int xpix, int ypix, int shift, int alt, int dbl, int doit);
/* save to a binbuf */
typedef void (*t_savefn)(t_gobj *x, t_binbuf *b);
/* open properties dialog */
typedef void (*t_propertiesfn)(t_gobj *x, struct _glist *glist);
/* ... and later, resizing; getting/setting font or color... */
struct _widgetbehavior
{
t_getrectfn w_getrectfn;
t_displacefn w_displacefn;
t_selectfn w_selectfn;
t_activatefn w_activatefn;
t_deletefn w_deletefn;
t_visfn w_visfn;
t_clickfn w_clickfn;
t_savefn w_savefn;
t_propertiesfn w_propertiesfn;
};
#elif !defined(PD_VERSION_MINOR)
#error Flext cannot be compiled with this version!
#else
#include <g_canvas.h>
#endif
static t_widgetbehavior widgetbehavior;
static void (*ori_vis)(t_gobj *c, t_glist *, int vis) = NULL;
void flext_base::SetAttrEditor(t_classid c)
{
// widgetbehavior struct MUST be resident... (static is just ok here)
widgetbehavior.w_getrectfn = c->c_wb->w_getrectfn;
widgetbehavior.w_displacefn = c->c_wb->w_displacefn;
widgetbehavior.w_selectfn = c->c_wb->w_selectfn;
widgetbehavior.w_activatefn = c->c_wb->w_activatefn;
widgetbehavior.w_deletefn = c->c_wb->w_deletefn;
ori_vis = c->c_wb->w_visfn;
widgetbehavior.w_visfn = cb_GfxVis;
widgetbehavior.w_clickfn = c->c_wb->w_clickfn;
widgetbehavior.w_propertiesfn = cb_GfxProperties;
widgetbehavior.w_savefn = cb_GfxSave;
class_setwidget(c, &widgetbehavior);
// generate the script for the property dialog
sys_gui(
"proc flext_apply {id alen} {\n"
// strip "." from the TK id to make a variable name suffix
"set vid [string trimleft $id .]\n"
// make a list of the attribute values (including save flags)
"set lst {}\n"
"for {set ix 0} {$ix < $alen} {incr ix} {\n"
"set var_attr_name [concat [concat var_name_$ix]_$vid ]\n"
"global $var_attr_name\n"
"set var_attr_val [concat [concat var_val_$ix]_$vid ]\n"
"global $var_attr_val\n"
"set var_attr_save [concat [concat var_save_$ix]_$vid ]\n"
"global $var_attr_save\n"
"lappend lst [eval concat $$var_attr_name]\n"
// see if it's a list
"set len [llength [expr $$var_attr_val]]\n"
"if { $len > 1 } {\n"
"set lst [concat $lst \"list\" $len [expr $$var_attr_val]]\n"
"} else {\n"
"lappend lst [expr $$var_attr_val]\n"
"}\n"
"lappend lst [eval concat $$var_attr_save]\n"
"}\n"
"set cmd [concat $id attributedialog $lst \\;]\n"
// puts stderr $cmd
"pd $cmd\n"
"}\n"
"proc flext_cancel {id} {\n"
"set cmd [concat $id cancel \\;]\n"
// puts stderr $cmd
"pd $cmd\n"
"}\n"
"proc flext_ok {id alen} {\n"
"flext_apply $id $alen\n"
"flext_cancel $id\n"
"}\n"
"proc pdtk_flext_dialog {id attrlist} {\n"
"set vid [string trimleft $id .]\n"
"set alen [expr [llength $attrlist] / 3 ]\n"
"toplevel $id\n"
"wm title $id {object attributes}\n"
"wm protocol $id WM_DELETE_WINDOW [concat flext_cancel $id]\n"
/*
"label $id.label -text {Attributes}\n"
"pack $id.label -side top\n"
*/
"set ix 0\n"
"foreach {an av asv} $attrlist {\n"
"set nm [concat $id.nm-$ix]\n"
"set var_attr_name [concat [concat var_name_$ix]_$vid ]\n"
"global $var_attr_name\n"
"set $var_attr_name $an\n"
"set var_attr_val [concat [concat var_val_$ix]_$vid ]\n"
"global $var_attr_val\n"
"set $var_attr_val $av\n"
"set var_attr_save [concat [concat var_save_$ix]_$vid ]\n"
"global $var_attr_save\n"
"set $var_attr_save $asv\n"
"frame $nm\n"
"pack $nm -side top\n"
"label $nm.lwidth -text \"$an :\"\n"
"entry $nm.width -textvariable $var_attr_val -width 20\n"
"checkbutton $nm.save -text {save} -variable $var_attr_save -anchor w\n"
"pack $nm.lwidth $nm.width $nm.save -side left\n"
"bind $nm.width <KeyPress-Return> [concat flext_ok $id $alen]\n"
"incr ix\n"
"}\n"
// "focus $id.1-rangef.width\n"
// Buttons
"frame $id.buttonframe\n"
"pack $id.buttonframe -side bottom -fill x -pady 2m\n"
"button $id.buttonframe.cancel -text {Cancel} -command \"flext_cancel $id\"\n"
"button $id.buttonframe.apply -text {Apply} -command \"flext_apply $id $alen\"\n"
"button $id.buttonframe.ok -text {OK} -command \"flext_ok $id $alen\"\n"
"pack $id.buttonframe.cancel -side left -expand 1\n"
"pack $id.buttonframe.apply -side left -expand 1\n"
"pack $id.buttonframe.ok -side left -expand 1\n"
"}\n"
);
}
void flext_base::cb_GfxProperties(t_gobj *c, t_glist *)
{
flext_base *th = thisObject(c);
char buf[1000],*b = buf;
AtomList la;
int cnt = th->ListAttrib(la);
STD::sprintf(b, "pdtk_flext_dialog %%s { "); b += strlen(b);
for(int i = 0; i < cnt; ++i) {
STD::sprintf(b,"%s {",GetString(la[i])); b += strlen(b);
bool sv;
// get attribute
attritem *attr = th->FindAttrib(GetSymbol(la[i]),true);
if(attr) {
// Attribute is gettable
// Get attribute value
AtomList lv;
th->GetAttrib(attr,lv);
sv = th->GetAttribSave(attr);
for(int j = 0; j < lv.Count(); ++j) {
if(IsString(lv[j]))
STD::sprintf(b,"%s",GetString(lv[j]));
else if(IsFloat(lv[j]))
STD::sprintf(b,"%f",GetFloat(lv[j]));
else if(IsInt(lv[j]))
STD::sprintf(b,"%i",GetInt(lv[j]));
else
FLEXT_ASSERT(false);
b += strlen(b);
if(j < lv.Count()-1) *(b++) = ' ';
}
}
else {
// Attribute is not gettable
sv = false;
// \TODO set flag for tcl/tk dialog
}
STD::sprintf(b, "} %i ", sv?1:0); b += strlen(b);
}
strcpy(b, " }\n");
gfxstub_new((t_pd *)th->thisHdr(), th->thisHdr(), buf);
}
void flext_base::cb_GfxVis(t_gobj *c, t_glist *gl, int vis)
{
flext_base *th = thisObject(c);
t_text *x = (t_text *)th->thisHdr();
FLEXT_ASSERT(x->te_binbuf);
int argc = binbuf_getnatom(x->te_binbuf);
t_atom *argv = binbuf_getvec(x->te_binbuf);
int cnt = CheckAttrib(argc,argv);
if(cnt) {
t_binbuf *nb = binbuf_new();
binbuf_restore(nb,cnt,argv);
binbuf_free(x->te_binbuf);
x->te_binbuf = nb;
}
ori_vis(c,gl,vis);
}
void flext_base::cb_GfxSave(t_gobj *c, t_binbuf *b)
{
flext_base *th = thisObject(c);
t_text *t = (t_text *)c;
binbuf_addv(b, "ssiis", gensym("#X"),gensym("obj"),
t->te_xpix, t->te_xpix,MakeSymbol(th->thisName())
// here the arguments
);
AtomList la;
int cnt = th->ListAttrib(la);
char attrname[100];
*attrname= '@';
for(int i = 0; i < cnt; ++i) {
// must be both settable and gettable....
attritem *attr = th->FindAttrib(GetSymbol(la[i]),true);
if(attr && attr->BothExist() && th->GetAttribSave(attr)) {
// Get attribute value
AtomList lv;
th->GetAttrib(attr,lv);
strcpy(attrname+1,GetString(la[i]));
binbuf_addv(b,"s",MakeSymbol(attrname));
for(int j = 0; j < lv.Count(); ++j) {
if(IsString(lv[j]))
binbuf_addv(b,"s",GetSymbol(lv[j]));
else if(IsFloat(lv[j]))
binbuf_addv(b,"f",GetFloat(lv[j]));
else if(IsInt(lv[j]))
binbuf_addv(b,"i",GetInt(lv[j]));
else
FLEXT_ASSERT(false);
}
}
}
binbuf_addv(b, ";");
}
bool flext_base::cb_AttrDialog(flext_base *th,int argc,const t_atom *argv)
{
int i = 0;
if(IsSymbol(argv[i]) && GetSymbol(argv[i]) == sym_list) ++i;
for(; i < argc; ) {
FLEXT_ASSERT(IsSymbol(argv[i]));
const t_symbol *aname = GetSymbol(argv[i]);
i++;
int cnt,offs;
if(IsSymbol(argv[i]) && GetSymbol(argv[i]) == sym_list) {
i++;
FLEXT_ASSERT(CanbeInt(argv[i]));
cnt = GetAInt(argv[i]);
offs = ++i;
}
else
offs = i,cnt = 1;
i += cnt;
FLEXT_ASSERT(i < argc);
bool sv = CanbeBool(argv[i]) && GetABool(argv[i]);
++i;
// find settable attribute
attritem *attr = th->FindAttrib(aname,false);
if(attr) {
th->SetAttribSave(attr,sv);
bool ret = th->SetAttrib(attr,cnt,argv+offs);
FLEXT_ASSERT(ret);
}
else {
post("%s - Attribute %s can't be set",th->thisName(),GetString(aname));
}
}
return true;
}
#endif // FLEXT_SYS_PD
......@@ -652,6 +652,8 @@ protected:
bool IsGet() const { return (flags&afl_getset) == afl_get; }
bool IsSet() const { return (flags&afl_getset) == afl_set; }
bool BothExist() const { return (flags&afl_bothexist) != 0; }
void SetSave(bool s) { if(s) flags |= afl_save; else flags &= ~afl_save; }
bool IsSaved() const { return (flags&afl_save) != 0; }
int flags;
metharg argtp;
......@@ -743,7 +745,7 @@ private:
itemarr *attrhead,*clattrhead;
attritem *FindAttr(const t_symbol *tag,bool get) const;
attritem *FindAttrib(const t_symbol *tag,bool get,bool msg = false) const;
static int CheckAttrib(int argc,const t_atom *argv);
bool InitAttrib(int argc,const t_atom *argv);
......@@ -755,6 +757,9 @@ private:
bool SetAttrib(const t_symbol *s,int argc,const t_atom *argv);
bool SetAttrib(attritem *a,int argc,const t_atom *argv);
void SetAttribSave(attritem *a,bool save);
bool GetAttribSave(attritem *a) const { return a->IsSaved(); }
static bool cb_ListMethods(flext_base *c,int argc,const t_atom *argv);
static bool cb_ListAttrib(flext_base *c) { return c->ListAttrib(); }
......@@ -766,6 +771,17 @@ private:
static void QFlush(flext_base *th = NULL);
#if FLEXT_SYS == FLEXT_SYS_PD
#if !defined(FLEXT_NOATTREDIT)
// attribute editor
static void SetAttrEditor(t_classid c);
static bool cb_AttrDialog(flext_base *c,int argc,const t_atom *argv);
static void cb_GfxProperties(t_gobj *c, t_glist *);
static void cb_GfxVis(t_gobj *c, t_glist *gl, int vis);
static void cb_GfxSave(t_gobj *c, t_binbuf *b);
#endif
// proxy object (for additional inlets)
static t_class *px_class;
......
......@@ -157,6 +157,11 @@ void flext_base::Setup(t_classid id)
if(process_attributes) {
AddMethod(id,0,"getattributes",cb_ListAttrib);
AddMethod(id,0,"getmethods",cb_ListMethods);
#if FLEXT_SYS == FLEXT_SYS_PD && !defined(FLEXT_NOATTREDIT)
AddMethod(id,0,"attributedialog",cb_AttrDialog);
SetAttrEditor(id);
#endif
}
SetProxies(c);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment