unit UMSample; {Contributed by Your Name } {Copyright is hereby waived: UMSample.p is in the public domain.} {User Macro "Sample" package. } {Macros which use these extensions should specify "requiresUser('Sample',1)".} {These instructions apply if you have received only UMSample.p and} {a copy of UMacroDef.p and UMacroRun.p, and want to install the code} {into your copy of NIH Image.} {You need the Think Pascal compiler to use this source code. } {Installation instructions. At the moment, the UMacroDef.p and UMacroRun.p} {have not been accepted for distribution with standard Image. If they are, then} {these instructions will apply. Otherwise, you will have to obtain a copy of image} {with UMacroDef.p etc. already installed. This will typically be available in} {the /pub/nih-image/contrib directory of zippy.nimh.nih.gov and the file} {name will include "UMX".} {If you have no other user macro extension packages installed,} {then just replace the default UMacroDef.p and UMacroRun.p with the enclosed} {versions. Otherwise, you must merge the changes, which should be found only} {at well marked places. Generally, this means simply adding lines, although you } {may also need to add a comma here and there. Changes should be found at} {one place in UMacroDef.p and seven places in UMacroRun.p.} {You will also have to use the "Project/Add File..." menu item to tell Think Pascal } {to compile this file, and use the "Windows/Image.proj" item to get the project window, } {and drag this file from the bottom of the list to somewhere between UMacroDef.p and } {UMacroRun.p.} {Finally, recompile and rebuild: Use "Run/Build" (command B) and } {"Project/Build Application...".} {--- Delete everything from here to the ==== line when making a new UMX module. ---} {The prototype module was contributed by Edward J. Huff } {Copyright is hereby waived: the prototype module is in the public domain.} {INSTRUCTIONS FOR CREATING A NEW EXTENSION PACKAGE} {To create a new Image Macro Language Extension Package "YourPack":} {First, read all of the instructions in UMacroDef.p including the} {comments on length of names: YourPack ought to be 8 characters or less.} {Next, complete the instructions below to create UMYourPack.p. } {Stop after point (5) below and follow the instructions in UMacroDef.p } {to add calls to the functions defined here. Basically, those instructions } {tell you to edit UMacroDef.p in one place and UMacroRun.p in seven places. } { Then complete points (6) to (9) below.} {If you later decide to add more macro commands or functions to} {your package, you will need to make changes at points (5) and (7)} {of UMacroRun.p, and also in three places in this module.} {(1)Use "File/Save a Copy AsÉ" to create UMYourPack.p from UMSample.p} {Do not use "File/Save As..." since that command does NOT do quite what is needed.} {WARNING: THE DEFAULT FOLDER IS ALMOST NEVER THE ONE YOU WANT.} {ALSO: IF YOU SAVE THE COPY IN THE WRONG FOLDER, YOU MAY NEVER NOTICE} {THE ERROR UNTIL YOU DISTRIBUTE JUST THE CONTENTS OF YOUR PROJECT FOLDER} {AND DISCOVER THAT IMAGE WILL NOT COMPILE BECAUSE OF A MISSING FILE.} {Choose "Project/View Options" and turn on the "volume name" check box and then } {examine the Project window (command zero) to make sure all .p files are in your} {folder and not in some unexpected place. Interface files like quickdraw.p belong} {in the Think Pascal Interfaces folder.} {Be sure to save it in the same folder as Image.proj, not in the Think Pascal folder.} {Note that after save a copy, this window will still be open and your copy will not } {be open.} {(2)Use "Project/Add FileÉ" to add UMYourPack.p to Image.proj.} {(3)Bring the Project window to the front by typing command zero or} {use Windows/Image.proj. Drag UMYourPack.p in the Image.proj } {window so it falls between UMacroDef.p and UMacroRun.p and turn off the "D" box } {(unless you want to use the Think Pascal debugger).} {(4)Open UMYourPack.p by double clicking in the Image.proj window. Delete} {these instructions from your file. Continue to read them in the UMSample.p window.} {(5)Use "Search/FindÉ" to search for "Sample", and replace with "YourPack".} {(Type "YourPack" into the "replace" box or "Search/Replace" will be dimmed.)} {Be sure to uncheck the "Whole Words" checkbox. Put it back on when done.} {Use "Search/Replace and Find again" (command D) to replace all occurances.} {Be sure the edits are done in UMYourPack.p, not in UMSample.p.} {Use "File/Save" or command S to save your file.} {At this point, it will be clearer if you go to UMacroDef.p and carry out the} {instructions there to create the definitions of your xxxUC symbols, etc.} {(6) In UMYourPackAdd, add a call to AddUMSym which specifies the } {name, the extension type, and the UserCommandType item. Extension types} {may be UserCommandT, UserFuncT, or UserStrFuncT.} {(7) In UMYourPackLookup, add an item to the case statement which specifies} {the number of arguments, and the type of each argument. Do not delete the} {otherwise clause without understanding why it is there (to help debug coding} {errors you might make in UMacroRun.p). } {Note that the value of atype must not be changed later. } {Also, nArgs must not be changed later.} {Restrictions: only one string argument. A string function may have } {a string argument but not a var string argument. } {(8) In UMYourPackRun, add an item to the case statement which actually does} {whatever your macro extension is supposed to do. It may be necessary} {to add units to the uses clause in the interface section.} { To report an error: } { ErrorOccurred := true;} { str := 'Error message';} { To set the return value of a function: } { FuncResult := value;} { To set the return value of a string function or the value of the string var argument:} { str := 'string function result';} { To set the value of a var argument (arg[n].atype must already be UMATvar) } { arg[n].aval := value;} { To save the value of the string argument (if any):} { strargsave := str;} {(9) Delete these instructions from your file. Also delete the savestring from the} {locals record and all code related to the sample macro commands. If you never} {plan to use any local static storage, also delete locals and code initializing it.} {=== end of instructions to delete === } interface uses QuickDraw, Palettes, PrintTraps, Globals, Utilities, UMacroDef; procedure UMSampleInit; procedure UMSampleFinal; procedure UMSampleAdd; procedure UMSampleLookup (var uma: UserMacroArgs); procedure UMSampleRun (var uma: UserMacroArgs); implementation {Local ("static") variables used by UMSample.p} {Space used here counts against the 32k byte limit on global variables,} {so allocate the space dynamically only if any of the macros are actually called.} {To determine how much global data is in use by the application as a whole} {and by each unit, select "Get Info" from the Project menu. You will see} {that UMSample.p uses only 4 bytes of global data even though it is capable} {of saving a 255 byte string.} type localsR = record saveString: Str255; end; localsP = ^localsR; localsH = ^localsP; var locals: localsH; {Called from procedure InitUserMacros in UMacroRun.p, } {which is called from Image.p early in initialization.} {Do not start timers (see UMTimer.p) in this function.} procedure UMSampleInit; begin locals := nil;{Do not allocate space unless needed} end; {Called from procedure FinalUserMacros in UMacroRun,p.} {This is guaranteed to run prior to any exit which happens after a call} {to DoUserMacro, and is intended for things which MUST be done prior } {to exit, like removing timers from the system timer list.} {Note well that it is NOT guaranteed to be called prior to any exit} {which might happen after InitUserMacros but before DoUserMacro.} procedure UMSampleFinal; begin end; {AddUMSym calls:} {Add one call for each macro command, function, or string function} {you wish to add to the macro language.} {First argument is a string, case is ignored, truncated to SymbolSize characters.} {Second argument must be one of UserCommandT, UserFuncT, or UserStrFuncT} {Third argument is the UserCommandType item associated with the name.} {Called from procedure AddUserMacros in UMacroRun.p.} {This runs once each time macros are loaded from a file or a text window.} procedure UMSampleAdd; begin AddUMSym('sampleCommand', UserCommandT, sampleCommandUC); AddUMSym('sampleFunc', UserFuncT, sampleFuncUC); AddUMSym('sampleStrFun', UserStrFuncT, sampleStrFuncUC); end; {Called from procedure LookupUserMacro in UMMacroRun.p} {This runs every time the macro is executed, just prior to} {parsing the arguments.} procedure UMSampleLookup (var uma: UserMacroArgs); begin with uma do case UserMacroCommand of sampleCommandUC: begin nArgs := 3; arg[1].atype := UMATreal; arg[2].atype := UMATstring; arg[3].atype := UMATrealvar; end; sampleFuncUC: begin nArgs := 1; arg[1].atype := UMATreal; end; sampleStrFuncUC: begin nArgs := 0; end; otherwise begin ErrorOccurred := true; str := 'UMSample.p LookupUserMacro'; end; end; end; {Called from procedure DoUserMacro in UMacroRun.p .} {Do not change uma.nArgs or uma.arg[i].argt here.} {This runs once each time the macro is used, after parsing the arguments.} procedure UMSampleRun (var uma: UserMacroArgs); begin if locals = nil then begin locals := localsH(getBigHandle(sizeof(localsR))); if locals = nil then with uma do begin ErrorOccurred := true; str := 'UMSample.p Out of memory'; Exit(UMSampleRun); end; HLock(Handle(locals)); locals^^.saveString := ''; end; HLock(Handle(locals)); with uma do case UserMacroCommand of sampleCommandUC: begin arg[3].aval := arg[1].aval; locals^^.saveString := str; end; sampleFuncUC: begin FuncResult := arg[1].aval + 1.0; end; sampleStrFuncUC: begin str := locals^^.saveString; end; otherwise begin ErrorOccurred := true; str := 'UMSample.p DoUserMacro'; end; end; HUnLock(Handle(locals)); end; end.