programmatic change of class attribute filter and enumval list?

diablodale's icon

In the Max SDK...
given an attribute "fooattrib" which is declared on a max class and points to a char field in the class struct
fooattrib is style=enumindex and enumvals="jane, sam" and filterset_clip=0,1
An object in Max has been created based on this class.

Now a state change happens in my external. I want to change the enumvals and filterset_clip to be...
enumvals="jane, sam, melonie" and filterset_clip=0,2

How can I achieve this? Or something similar to this? I have yet to find a way to redefine attr's of attr's of classes. That would be great because then I could make the change and it would cascade to all the objects instantiated.

If not possible to do something like that just mentioned, could I define the class *minus* fooattrib and then on object instantiation create a object attribute on that specific object...and then somehow later during this state change delete/change that specific object attribute?

Ideas?

Luigi Castelli's icon

Hi Diablodale,

since no C74 guru has replied yet, I will give you an example of how this could be accomplished:

Let's say you have two attributes "foonames" and "fooattrib".
We will change the enumindex and filter_clip of "fooattrib" programmatically, based on the values that "foonames" takes on.

#define MAX_NAMES 64

typedef struct _myobj
{
    t_jbox          box;
    t_symbol        *foonames[MAX_NAMES];
    long            foonamecount;
    char            fooattrib;
} t_myobj;

in main we define two class attributes...

CLASS_ATTR_SYM_VARSIZE(c,           "foonames",         ATTR_FLAGS_NONE, t_myobj, foonames, foonamecount, MAX_NAMES);
CLASS_ATTR_DEFAULT_SAVE_PAINT(c,    "foonames",         ATTR_FLAGS_NONE, "Jane Sam");
    
CLASS_ATTR_CHAR(c,                  "fooattrib",        ATTR_FLAGS_NONE, t_myobj, fooattrib);
CLASS_ATTR_ENUMINDEX(c,             "fooattrib",        ATTR_FLAGS_NONE, "Jane Sam");
CLASS_ATTR_DEFAULT_SAVE_PAINT(c,    "fooattrib",        ATTR_FLAGS_NONE, "0");
CLASS_ATTR_FILTER_CLIP(c,        "fooattrib",        0, 1);

the magic happens in the notify function...

t_max_err myobj_notify(t_myobj *x, t_symbol *sym, t_symbol *msg, void *sender, void *data)
{
    t_object *attr;
    t_object *attr2;
    t_symbol *attrname;
    
    if (msg == gensym("attr_modified")) {
        attr = (t_object *)data;
    attrname = (t_symbol *)object_method(attr, gensym("getname"));
    if (attrname == gensym("foonames")) {
            attr2 = object_attr_get(x, gensym("fooattrib"));
            if (attr2) {
                t_atom argv[MAX_NAMES];
                long argc = x->foonamecount;
                long i;
                
                // update enumvals
                for (i = 0; i < argc; i++) {
                    atom_setsym(argv+i, x->foonames[i]);
                }
                object_attr_setvalueof(attr2, gensym("enumvals"), argc, argv);
                
                // update filter_clip
                attr_addfilter_clip(attr2, 0, argc-1, 1, 1);
                
                // check that fooattrib is still in range
                if (x->fooattrib >= argc) {
                    x->fooattrib = argc-1;
                }
                    
                // notify that attribute has been changed
                object_notify(x, gensym("attr_modified"), attr2);
            }
        }
    }
    return jbox_notify((t_jbox *)x, sym, msg, sender, data);
}

There is one thing I am not 100% sure about:
when calling attr_addfilter_clip() there should be a new filter_clip object being created and added to the attribute.
I am not sure what happens to the previous filter_clip object...
Logically it should be freed but since I have no access to the C74 codebase I cannot guarantee it.
If it doesn't get freed then we have a memory leak. I don't know if the Max API makes provisions for it to be changed dynamically after creation. I can tell you that in my short and quick tests the code works without problems though.

This could suggest that instead of using a filter_clip object, it could be better to use a custom setter for "fooattrib" and manage the clipping in there. Perhaps this could be a better alternative...

Hope this helps

- Luigi

Luigi Castelli's icon

It would be nice to know what strategy you ended up using and if you go it working in the end...

- Luigi