Max 5 API Reference
00001 /** 00002 @file 00003 iterator - patch iterator 00004 jeremy bernstein - jeremy@bootsquad.com 00005 00006 @ingroup examples 00007 */ 00008 00009 #include "ext.h" // standard Max include, always required 00010 #include "ext_obex.h" // required for new style Max object 00011 #include "jpatcher_api.h" 00012 00013 ////////////////////////// object struct 00014 typedef struct _iterator 00015 { 00016 t_object a_ob; // the object itself (must be first) 00017 t_object *a_patcher; // pointer to our patcher 00018 t_object *a_patcherview; // pointer to our first patcherview 00019 t_pt a_cached; 00020 } t_iterator; 00021 00022 ///////////////////////// function prototypes 00023 //// standard set 00024 void *iterator_new(t_symbol *s, long argc, t_atom *argv); 00025 void iterator_free(t_iterator *x); 00026 void iterator_assist(t_iterator *x, void *b, long m, long a, char *s); 00027 //// additional methods 00028 void iterator_bang(t_iterator *x); // incoming bang message 00029 void iterator_notify(t_iterator *x, t_symbol *s, t_symbol *msg, void *sender, void *data); 00030 void iterator_attach(t_iterator *x); 00031 00032 //////////////////////// global class pointer variable 00033 void *iterator_class; 00034 00035 int main(void) 00036 { 00037 t_class *c; 00038 00039 c = class_new("iterator", (method)iterator_new, (method)iterator_free, sizeof(t_iterator), 0L, A_GIMME, 0); 00040 00041 class_addmethod(c, (method)iterator_bang, "bang", 0); 00042 class_addmethod(c, (method)iterator_assist, "assist", A_CANT, 0); 00043 class_addmethod(c, (method)iterator_notify, "notify", A_CANT, 0); 00044 00045 class_register(CLASS_BOX, c); 00046 iterator_class = c; 00047 00048 post("I am the iterator object"); 00049 return 0; 00050 } 00051 00052 void iterator_assist(t_iterator *x, void *b, long m, long a, char *s) 00053 { 00054 if (m == ASSIST_INLET) { //inlet 00055 sprintf(s, "I am inlet %ld", a); 00056 } 00057 else { // outlet 00058 sprintf(s, "I am outlet %ld", a); 00059 } 00060 } 00061 00062 void iterator_bang(t_iterator *x) 00063 { 00064 t_object *jp; 00065 t_object *jb; 00066 t_object *mybox; 00067 t_object *o; 00068 t_rect jr; 00069 t_symbol *scriptingname; 00070 t_max_err err; 00071 00072 // get the object's parent patcher 00073 err = object_obex_lookup(x, gensym("#P"), (t_object **)&jp); 00074 if (err != MAX_ERR_NONE) 00075 return; 00076 00077 // get the object's wrapping box 00078 err = object_obex_lookup(x, gensym("#B"), (t_object **)&mybox); 00079 if (err != MAX_ERR_NONE) 00080 return; 00081 00082 jb = jpatcher_get_firstobject(jp); // get the first BOX in the object list 00083 00084 while(jb) { 00085 jbox_get_patching_rect(jb, &jr); // x, y, width, height (double) 00086 00087 object_post((t_object *)x, "found an object at %ld %ld, w %ld, h %ld", (long)jr.x, (long)jr.y, (long)jr.width, (long)jr.height); 00088 00089 scriptingname = jbox_get_varname(jb); // scripting name 00090 if (scriptingname && scriptingname != gensym("")) 00091 object_post((t_object *)x, " it is named %s...", scriptingname->s_name); 00092 00093 o = jbox_get_object(jb); // get the box's object (b_firstin in Max4) 00094 post(" it's a(n) %s object...", object_classname(o)->s_name); 00095 00096 if (jpatcher_is_patcher(o)) { 00097 post(" which is some kind of a patcher. we could recurse here..."); 00098 } 00099 00100 if (jb == mybox) 00101 post(" ...and it's me!"); 00102 00103 jb = jbox_get_nextobject(jb); // iterate 00104 } 00105 00106 // jbox_get_patcher(abox); // get a box's patcher 00107 00108 // maybe upwards? jpatcher_get_parentpatcher(<#t_object * p#>) 00109 } 00110 00111 void iterator_notify(t_iterator *x, t_symbol *s, t_symbol *msg, void *sender, void *data) 00112 { 00113 // post("got %s message from %X (%s)", msg->s_name, sender, s->s_name); 00114 if (msg == gensym("attr_modified") && sender == x->a_patcherview) { // sent when an attribute of the sender changes 00115 t_symbol *attrname; 00116 00117 // 'data' arg is the modified attribute object 00118 // get its name: 00119 attrname = (t_symbol *)object_method(data, gensym("getname")); 00120 post("'%s' attribute was modified", attrname->s_name); 00121 00122 if (attrname == gensym("rect")) { 00123 t_atom *av = NULL; 00124 long ac = 0; 00125 00126 object_attr_getvalueof(sender, attrname, &ac, &av); 00127 if (ac && av) { 00128 t_object *jb; 00129 00130 post("new rect: %ld %ld %ld %ld", atom_getlong(av), atom_getlong(av+1), atom_getlong(av+2), atom_getlong(av+3)); 00131 object_obex_lookup(x, gensym("#B"), &jb); 00132 if (jb) { 00133 t_atom *rv = NULL; 00134 long rc = 0; 00135 00136 object_attr_getvalueof(jb, gensym("patching_rect"), &rc, &rv); 00137 if (rc && rv) { 00138 // we have box rect 00139 // compare cached view size to current view 00140 long dx = atom_getlong(av+2) - x->a_cached.x; 00141 long dy = atom_getlong(av+3) - x->a_cached.y; 00142 long boxw = atom_getlong(rv+2); 00143 long boxh = atom_getlong(rv+3); 00144 00145 // recache new size 00146 x->a_cached.x = atom_getlong(av+2); 00147 x->a_cached.y = atom_getlong(av+3); 00148 00149 // modify my box width 00150 atom_setlong(rv+2, boxw + dx); 00151 // (height is ignored by jnewobj) 00152 atom_setlong(rv+3, boxh + dy); 00153 object_attr_setvalueof(jb, gensym("patching_rect"), rc, rv); 00154 freebytes(rv, sizeof(t_atom) * rc); 00155 } 00156 } 00157 freebytes(av, sizeof(t_atom) * ac); 00158 } 00159 } 00160 00161 } 00162 00163 } 00164 00165 void iterator_free(t_iterator *x) 00166 { 00167 t_object *jp = NULL; 00168 t_object *pv; 00169 00170 // detach from any objects that you have attached to. 00171 object_obex_lookup(x, gensym("#P"), &jp); 00172 if (jp) { 00173 pv = jpatcher_get_firstview(jp); 00174 object_detach_byptr(x, pv); 00175 } 00176 } 00177 00178 void *iterator_new(t_symbol *s, long argc, t_atom *argv) 00179 { 00180 t_iterator *x = NULL; 00181 00182 if (x = (t_iterator *)object_alloc(iterator_class)) { 00183 00184 // Get a pointer to our patcher 00185 object_obex_lookup(x, gensym("#P"), &x->a_patcher); 00186 00187 // The patcherview is not available when the object is created as a patcher is being read from disk, 00188 // so we have to defer to wait for it before getting it and attaching for notifications. 00189 defer_low(x, (method)iterator_attach, NULL, 0, NULL); 00190 } 00191 return (x); 00192 } 00193 00194 void iterator_attach(t_iterator *x) 00195 { 00196 t_atom *av = NULL; 00197 long ac = 0; 00198 00199 x->a_patcherview = object_attr_getobj(x->a_patcher, gensym("firstview")); 00200 object_attach_byptr_register(x, x->a_patcherview, CLASS_NOBOX); 00201 00202 // get the bounds of the first patcherview and cache them 00203 object_attr_getvalueof(x->a_patcherview, gensym("rect"), &ac, &av); 00204 if (ac && av) { 00205 x->a_cached.x = atom_getfloat(av+2); // width 00206 x->a_cached.y = atom_getfloat(av+3); // height 00207 freebytes(av, sizeof(t_atom) * ac); // or sysmem_freeptr() 00208 } 00209 }
Copyright © 2008, Cycling '74