Max 5 API Reference
00001 /** 00002 @page chapter_scripting Scripting the Patcher 00003 00004 Your object can use scripting capabilities of the patcher to learn things about its context, such as the patcher's name, hierarchy, or the peer objects to your object in its patcher. 00005 00006 You can also modify a patcher, although any actions your object takes are not undoable and may not work in the runtime version. 00007 00008 00009 @section chapter_scripting_knowing Knowing the Patcher 00010 00011 To obtain the patcher object containing your object, you can use the obex hash table. The obex (for "object extensions") is, more generally, a way to store and recall data in your object. In this case, however, we are just using it in a read-only fashion. 00012 00013 Note that unlike the technique discussed in previous versions of the SDK, using the obex to find the patcher works at any time, not just in the new instance routine. 00014 00015 @code 00016 void myobject_getmypatcher(t_myobject *x) 00017 { 00018 t_object *mypatcher; 00019 00020 obex_object_lookup(x, gensym("#P"), &mypatcher); 00021 post("my patcher is at address %lx",mypatcher); 00022 } 00023 @endcode 00024 00025 The patcher is an opaque Max object. To access data in a patcher, you'll use attributes and methods. 00026 00027 00028 @subsection chapter_scripting_knowing_name Patcher Name and File Path 00029 00030 To obtain the name of the patcher and its file path (if any), obtain attribute values as shown below. 00031 @code 00032 t_symbol *name = object_attr_getsym(patcher, gensym("name")); 00033 t_symbol *path = object_attr_getsym(patcher, gensym("filepath")); 00034 @endcode 00035 00036 These attributes may return NULL or empty symbols. 00037 00038 00039 @subsection chapter_scripting_knowing_heirarchy Patcher Hierarchy 00040 00041 To determine the patcher hierarchy above the patcher containing your object, you can use jpatcher_getparentpatcher(). A patcher whose parent is NULL is a top-level patcher. Here is a loop that prints the name of each parent patcher as you ascend the hierarchy. 00042 00043 @code 00044 t_object *parent, *patcher; 00045 t_symbol *name; 00046 00047 object_obex_lookup(x, gensym("#P"), &patcher); 00048 parent = patcher; 00049 do { 00050 parent = jpatcher_getparentpatcher(parent); 00051 if (parent) { 00052 name = object_attr_getsym(parent, gensym("name")); 00053 if (name) 00054 post("%s",name->s_name) 00055 } 00056 } while (parent != NULL); 00057 @endcode 00058 00059 00060 @subsection chapter_scripting_knowing_objects Getting Objects in a Patcher 00061 00062 To obtain the first object in a patcher, you can use jpatcher_get_firstobject(). Subsequent objects are available with jbox_get_nextobject(). 00063 00064 If you haven't read the @ref chapter_ui_anatomy, we'll mention that the patcher does not keep a list of non-UI objects directly. Instead it keeps a list of UI objects called boxes, and the box that holds non-UI objects is called a newobj. The "objects" you obtain with calls such as jpatcher_get_firstobject() are boxes. The jbox_get_object() routine can be used to get the pointer to the actual object, whether the box is a UI object or a newobj containing a non-UI object. In the case of UI objects such as dials and sliders, the pointer returned by jbox_get_object() will be the same as the box. But for non-UI objects, it will be different. 00065 00066 Here is a function that prints the class of every object (in a box) in a patcher containing an object. 00067 @code 00068 void myobject_printpeers(t_myobject *x) 00069 { 00070 t_object *patcher, *box, *obj; 00071 00072 object_obex_lookup(x, gensym("#P"), &patcher); 00073 00074 for (box = jpatcher_get_firstobject(patcher); box; jbox_get_nextobject(box)) { 00075 obj = jbox_get_object(box); 00076 if (obj) 00077 post("%s",object_classname(obj)->s_name); 00078 else 00079 post("box with NULL object"); 00080 } 00081 } 00082 @endcode 00083 00084 00085 @subsection chapter_scripting_knowing_iteration Iteration Using Callbacks 00086 00087 As an alternative to the technique shown above, you can write a callback function for use with the patcher's iteration service. The advantage of using iteration is that you can descend into the patcher hierarchy without needing to know the details of the various objects that may contain subpatchers (patcher, poly~, bpatcher, etc.). If you want to iterate only at one level of a patcher hierarchy, you can do that too. 00088 00089 Your iteration function is defined as follows. It will be called on every box in a patcher (and, if you specify, the patcher's subpatchers). 00090 @code 00091 long myobject_iterarator(t_myobject *x, t_object *b); 00092 @endcode 00093 00094 The function returns 0 if iteration should continue, or 1 if it should stop. This permits you to use an iterator as a way to search for a specific object. 00095 00096 Here is an example of using an iterator function: 00097 00098 @code 00099 t_object *patcher; 00100 long result = 0; 00101 00102 patcher = object_obex_lookup(x, gensym("#P"), &patcher); 00103 00104 object_method(patcher, gensym("iterate"), myobject_iterator, (void *)x, PI_WANTBOX | PI_DEEP, &result); 00105 @endcode 00106 00107 The #PI_WANTBOX flag tells the patcher iterator that it should pass your iterator function the box, rather than the object contained in the box. The #PI_DEEP flag means that the iteration will descend, depth first, into subpatchers. The result parameter returns the last value returned by the iterator. For example, if the iterator terminates early by returning a non-zero value, it will contain that value. If the iterator function does not terminate early, result will be 0. 00108 00109 Assuming the iterator function receives boxes, here is an example iterator that prints out the class and scripting name (if any) of all of the objects in a patcher. Note that the scripting name is an attribute of the box, while the class we would like to know is of the object associated with the box. 00110 00111 @code 00112 long myobject_iterator(t_myobject *x, t_object *b) 00113 { 00114 t_symbol *name = object_attr_getsym(b, gensym("varname")); 00115 t_symbol *cls = object_classname(jbox_get_object(b)); 00116 00117 if (name) 00118 post("%s (%s)",cls->s_name, name->s_name); 00119 else 00120 post("%s", cls->s_name); 00121 return 0; 00122 } 00123 @endcode 00124 00125 00126 @section chapter_scripting_objects Creating Objects 00127 00128 Much of the Max user interface is implemented using patcher scripting. For example, the inspectors are patchers in which an inspector object has been created. The file browser window has four or five separate scripted objects in it. Even the debug window is a dynamically scripted patcher. We point this out just to inform you that creating objects in a patcher actually works (if you get all the details right). The xxx example object shows how to use patcher scripting to create an "editing window" similar to the ones you see when double-clicking on a table or buffer~ object. 00129 00130 Creating objects in a patcher generally requires the use of a @ref dictionary (see discussion of UI objects above), but there is a convenience function newobject_sprintf() that can be used to avoid some of the complexity. 00131 00132 To create an object, your task is to set some attributes. In the absence of any specific values, an object's attributes will be set to some default, but you'll probably care, at the very least, about specifying the object's location. Here is an example that creates a toggle and metro object using a combination of attribute parse syntax and sprintf. If you're interested in creating objects with newobject_sprintf(), it may help to examine a Max document to see some of the attribute name - value pairs used to specify objects. 00133 00134 @code 00135 t_object *patcher, *toggle, *metro; 00136 00137 patcher = object_obex_lookup(x, gensym("#P"), &patcher); 00138 00139 toggle = newobject_sprintf(patcher, "@maxclass toggle @patching_position %.2f %.2f", 00140 x->togxpos, x-> togxpos); 00141 00142 metro = newobject_sprintf(patcher, "@maxclass newobj @text metro 400 @patching_position %.2f %.2f", 00143 x->metxpos, x->metypos); 00144 @endcode 00145 00146 Note that to create a non-UI object, you use set the maxclass attribute to newobj and the text attribute to the contents of the object box. Attributes can be specified in any order. Using the patching_position attribute permits you to specify only the top-left corner and use the object's default size. For text objects, the default size is based on the default font for the patcher. 00147 00148 Finally, note that newobject_sprintf() returns a pointer to the newly created box, not the newly created object inside the box. To get the object inside the box, use jbox_get_object(). 00149 00150 00151 @subsection chapter_scripting_objects_connecting Connecting Objects 00152 00153 If you'd like to script the connections between two objects, you can do so via a message to the patcher. Assuming you have the patcher, toggle, and metro objects above, you'll create an array of atoms to send the message using object_method_typed(). 00154 00155 @code 00156 t_atom msg[4], rv; 00157 00158 atom_setobj(msg, toggle); // source 00159 atom_setlong(msg + 1, 0); // outlet number (0 is leftmost) 00160 atom_setobj(msg + 2, metro); // destination 00161 atom_setlong(msg + 3, 0); // inlet number (0 is leftmost) 00162 00163 object_method_typed(patcher, gensym("connect"), 4, msg, &rv); 00164 @endcode 00165 00166 If you want to have a hidden connection, pass an optional fifth argument that is any negative number. 00167 00168 00169 @section chapter_scripting_objects_deleting Deleting Objects 00170 00171 To delete an object in a patcher you call object_free() on the box. 00172 As of Max 5.0.6 this will properly redraw the patcher and remove any connected patch cords. 00173 00174 00175 @section chapter_scripting_attrs Obtaining and Changing Patcher and Object Attributes 00176 00177 You can use object attribute functions to modify the appearance and behavior of objects in a patcher or the patcher itself. Note that only a few of these attributes can be modified by the user. The C level access to attributes is much more extensive. 00178 00179 Attributes whose type is object can be accessed via object_attr_getobj() / object_attr_setobj(). Attributes whose type is char can be accessed with object_attr_getchar() / object_attr_setchar(). Attributes whose type is long can be accessed with object_attr_getlong() / object_attr_setlong(). Attributes whose type is symbol can be accessed via object_attr_getsym() / object_attr_setsym(). For attributes that are arrays, such as colors and rectangles, use object_attr_getvalueof() / object_attr_setvalueof(). 00180 00181 00182 @subsection chapter_scripting_attrs_patcher Patcher Attributes 00183 00184 <table> 00185 <tr><td>Name </td><td>Type </td><td>Settable </td><td>Description</td></tr> 00186 <tr><td>box </td><td>object </td><td>No </td><td>The box containing the patcher (NULL for top-level patcher) </td></tr> 00187 <tr><td>locked </td><td>char </td><td>Yes (not in runtime) </td><td>Locked state of the patcher </td></tr> 00188 <tr><td>presentation </td><td>char </td><td>Yes </td><td>Presentation mode of the patcher </td></tr> 00189 <tr><td>openinpresentation </td><td>char </td><td>Yes </td><td>Will patcher open in presentation mode? </td></tr> 00190 <tr><td>count </td><td>long </td><td>No </td><td>Number of objects in a patcher </td></tr> 00191 <tr><td>fgcount </td><td>long </td><td>No </td><td>Number of objects in the patcher's foreground layer </td></tr> 00192 <tr><td>bgcount </td><td>long </td><td>No </td><td>Number of objects in the patcher's background layer </td></tr> 00193 <tr><td>numvews </td><td>long </td><td>No </td><td>Number of currently open views of the patcher </td></tr> 00194 <tr><td>numwindowviews </td><td>long </td><td>No </td><td>Number of currently open window-based views of the patcher </td></tr> 00195 <tr><td>firstobject </td><td>object </td><td>No </td><td>First box in the patcher </td></tr> 00196 <tr><td>lastobject </td><td>object </td><td>No </td><td>Last box in the patcher </td></tr> 00197 <tr><td>firstline </td><td>object </td><td>No </td><td>First patch cord in the patcher </td></tr> 00198 <tr><td>firstview </td><td>object </td><td>No </td><td>First view object in the patcher </td></tr> 00199 <tr><td>title </td><td>symbol </td><td>Yes </td><td>Window title </td></tr> 00200 <tr><td>fulltitle </td><td>symbol </td><td>No </td><td>Complete title including "unlocked" etc. </td></tr> 00201 <tr><td>name </td><td>symbol </td><td>No </td><td>Name (could be different from title) </td></tr> 00202 <tr><td>filename </td><td>symbol </td><td>No </td><td>Filename </td></tr> 00203 <tr><td>filepath </td><td>symbol </td><td>No </td><td>File path (platform-independent file path syntax) </td></tr> 00204 <tr><td>fileversion </td><td>long </td><td>No </td><td>File version </td></tr> 00205 <tr><td>noedit </td><td>char </td><td>No </td><td>Whether patcher can be unlocked </td></tr> 00206 <tr><td>collective </td><td>object </td><td>No </td><td>Collective object, if patcher is inside a collective </td></tr> 00207 <tr><td>cansave </td><td>char </td><td>No </td><td>Whether patcher can be saved </td></tr> 00208 <tr><td>dirty </td><td>char </td><td>Yes (not in runtime) </td><td>Whether patcher is modified </td></tr> 00209 <tr><td>bglocked </td><td>char </td><td>Yes </td><td>Whether background is locked </td></tr> 00210 <tr><td>rect </td><td>double[4] </td><td>Yes </td><td>Patcher's rect (left, top, width, height) </td></tr> 00211 <tr><td>defrect </td><td>double[4] </td><td>Yes </td><td>Patcher's default rect (used when opening the first view) </td></tr> 00212 <tr><td>openrect </td><td>double[4] </td><td>Yes </td><td>Fixed initial window location </td></tr> 00213 <tr><td>parentpatcher </td><td>object </td><td>No </td><td>Immediate parent patcher (NULL for toplevel patchers) </td></tr> 00214 <tr><td>toppatcher </td><td>object </td><td>No </td><td>Topmost parent patcher (NULL for toplevel patchers) </td></tr> 00215 <tr><td>parentclass </td><td>object </td><td>No </td><td>Class object of parent (patcher, poly~, bpatcher etc.) </td></tr> 00216 <tr><td>bgcolor </td><td>double[4] </td><td>Yes </td><td>Locked background color (RGBA) </td></tr> 00217 <tr><td>editing_bgcolor </td><td>double[4] </td><td>Yes </td><td>Unlocked background color (RGBA) </td></tr> 00218 <tr><td>edit_framecolor </td><td>double[4] </td><td>Yes </td><td>Text editing frame color </td></tr> 00219 <tr><td>locked_iocolor </td><td>double[4] </td><td>Yes </td><td>Locked inlet/outlet color </td></tr> 00220 <tr><td>unlocked_iocolor </td><td>double[4] </td><td>Yes </td><td>Unlocked inlet/outlet color </td></tr> 00221 <tr><td>boguscolor </td><td>double[4] </td><td>Yes </td><td>Color of uninitialized (bogus) objects </td></tr> 00222 <tr><td>gridsize </td><td>double[2] </td><td>Yes </td><td>Editing grid size </td></tr> 00223 <tr><td>gridonopen </td><td>char </td><td>Yes </td><td>Show grid on open </td></tr> 00224 <tr><td>gridsnapopen </td><td>char </td><td>Yes </td><td>Snap to grid on open </td></tr> 00225 <tr><td>imprint </td><td>char </td><td>Yes </td><td>Save default-valued object attributes </td></tr> 00226 <tr><td>defaultfocusbox </td><td>symbol </td><td>Yes </td><td>Default focus box (varname) </td></tr> 00227 <tr><td>enablehscroll </td><td>char </td><td>Yes </td><td>Show horizontal scrollbar </td></tr> 00228 <tr><td>enablevscroll </td><td>char </td><td>Yes </td><td>Show vertical scrollbar </td></tr> 00229 <tr><td>boxanimatetime </td><td>long </td><td>Yes </td><td>Box animation time </td></tr> 00230 <tr><td>default_fontname </td><td>symbol </td><td>Yes </td><td>Default font name </td></tr> 00231 <tr><td>default_fontface </td><td>long </td><td>Yes </td><td>Default "fake" font face (0 plain, 1, bold, 2 italic, 3 bold italic) </td></tr> 00232 <tr><td>default_fontsize </td><td>long </td><td>Yes </td><td>Default font size in points </td></tr> 00233 <tr><td>toolbarvisible </td><td>char </td><td>Yes </td><td>Show toolbar on open </td></tr> 00234 <tr><td>toolbarheight </td><td>long </td><td>Yes </td><td>Height of toolbar (can use 0 for invisible) </td></tr> 00235 <tr><td>toolbarid </td><td>symbol </td><td>Yes </td><td>Name (in maxinterface.json) of toolbar, none = empty symbol </td></tr> 00236 </table> 00237 00238 00239 @subsection chapter_scripting_attrs_box Box Attributes 00240 00241 <table> 00242 <tr><td>Name </td><td>Type </td><td>Settable </td><td>Description</td></tr> 00243 <tr><td>rect </td><td>double[4] </td><td>Settable only </td><td>Changes both patching_rect and presentation_rect </td></tr> 00244 <tr><td>presentation_rect </td><td>double[4] </td><td>Yes </td><td>Presentation mode rect </td></tr> 00245 <tr><td>patching_rect </td><td>double[4] </td><td>Yes </td><td>Patching mode rect </td></tr> 00246 <tr><td>position </td><td>double[2] </td><td>Settable only </td><td>Changes both patching_position and presentation_position </td></tr> 00247 <tr><td>size </td><td>double[2] </td><td>Settable only </td><td>Changes both patching_size and presentation_size </td></tr> 00248 <tr><td>patching_position </td><td>double[2] </td><td>Yes </td><td>Patching mode position (top, left corner) </td></tr> 00249 <tr><td>presentation_position</td><td>d[2] </td><td>Yes </td><td>Presentation mode position </td></tr> 00250 <tr><td>patching_size </td><td>double[2] </td><td>Yes </td><td>Patching mode size (width, height) </td></tr> 00251 <tr><td>presentation_size </td><td>double[2] </td><td>Yes </td><td>Presentation mode size </td></tr> 00252 <tr><td>maxclass </td><td>symbol </td><td>No </td><td>Name of Max class (newobj for non-UI objects) </td></tr> 00253 <tr><td>object </td><td>object </td><td>No </td><td>Associated object (equivalent to jbox_get_object) </td></tr> 00254 <tr><td>patcher </td><td>object </td><td>No </td><td>Containing patcher </td></tr> 00255 <tr><td>hidden </td><td>char </td><td>Yes </td><td>Is box hidden on lock? </td></tr> 00256 <tr><td>fontname </td><td>symbol </td><td>Yes </td><td>Font name (if box has font attributes or a text field) </td></tr> 00257 <tr><td>fontface </td><td>long </td><td>Yes </td><td>"Fake" font face (if box has font attribute or a text field) </td></tr> 00258 <tr><td>fontsize </td><td>long </td><td>Yes </td><td>Font size (if box has font attributes or a text field) </td></tr> 00259 <tr><td>textcolor </td><td>double[4] </td><td>Yes </td><td>Text color (if box has font attributes or a text field) </td></tr> 00260 <tr><td>hint </td><td>symbol </td><td>Yes </td><td>Associated hint </td></tr> 00261 <tr><td>color </td><td>double[4] </td><td>Yes </td><td>Standard color attribute (may not be present in all objects) </td></tr> 00262 <tr><td>nextobject </td><td>object </td><td>No </td><td>Next object in the patcher's list </td></tr> 00263 <tr><td>prevobject </td><td>object </td><td>No </td><td>Previous object in the patcher's list </td></tr> 00264 <tr><td>varname </td><td>symbol </td><td>Yes </td><td>Scripting name </td></tr> 00265 <tr><td>id </td><td>symbol </td><td>No </td><td>Immutable object ID (stored in files) </td></tr> 00266 <tr><td>canhilite </td><td>char </td><td>No </td><td>Does this object accept focus? </td></tr> 00267 <tr><td>background </td><td>char </td><td>Yes </td><td>Include in background </td></tr> 00268 <tr><td>ignoreclick </td><td>char </td><td>Yes </td><td>Ignores clicks </td></tr> 00269 <tr><td>maxfilename </td><td>symbol </td><td>No </td><td>Filename if class is external </td></tr> 00270 <tr><td>description </td><td>symbol </td><td>No </td><td>Description used by assistance </td></tr> 00271 <tr><td>drawfirstin </td><td>char </td><td>No </td><td>Is leftmost inlet drawn? </td></tr> 00272 <tr><td>growy </td><td>char </td><td>No </td><td>Can object grow with fixed aspect ratio? </td></tr> 00273 <tr><td>growboth </td><td>char </td><td>No </td><td>Can object grow independently in width and height? </td></tr> 00274 <tr><td>nogrow </td><td>char </td><td>No </td><td>Is object fixed size? </td></tr> 00275 <tr><td>mousedragdelta </td><td>char </td><td>No </td><td>Does object use hidden-mouse drag tracking (number box) </td></tr> 00276 <tr><td>textfield </td><td>object </td><td>No </td><td>Textfield object associated with this box if any </td></tr> 00277 <tr><td>editactive </td><td>char </td><td>No </td><td>Is object the currently focused box in an unlocked patcher? </td></tr> 00278 <tr><td>prototypename </td><td>symbol </td><td>No </td><td>Name of the prototype file used to create this object </td></tr> 00279 <tr><td>presentation </td><td>char </td><td>Yes </td><td>Is object included in the presentation? </td></tr> 00280 <tr><td>annotation </td><td>symbol </td><td>Yes </td><td>Text shown in clue window when mouse is over the object </td></tr> 00281 <tr><td>numinlets </td><td>long </td><td>No </td><td>Number of inlets visible </td></tr> 00282 <tr><td>numoutlets </td><td>long </td><td>No </td><td>Number of outlets visible </td></tr> 00283 <tr><td>outlettype </td><td>symbol[] </td><td>No </td><td>Array of symbols with outlet types ("signal" etc.) </td></tr> 00284 </table> 00285 00286 To access an attribute of a non-UI object, use jbox_get_object() on the box to obtain the non-UI object first. 00287 00288 00289 */
Copyright © 2008, Cycling '74