|
C plug-ins can now take advantage of the LScript Universal Requester mechanism.
This service, provided by the LCore subsystem, allows C plug-ins to use LScript's
requester mechanism to create their user interfaces using LScript code. This
system allows C plug-ins to retrieve the result of the requester (i.e., whether
"Ok" or "Cancel" was press), as well as set the initial control values and
retrieve the resulting values when the requester is dismissed.
The LScript code that implements the requester, written either by hand or
generated by the LSIDE Interface Designer, is stored in a NULL-terminated array
of character strings. This array is then passed to the Universal Requester
mechanism for compilation:
const char *ui_script[] = {
"options",
"{",
"reqbegin(\"LScript Universal Requester test\");",
"c1 = ctlnumber(\"Number\",lsur_num);",
"if(reqpost())",
"lsur_num = getvalue(c1);",
"reqend();",
"}",
NULL
};
...
int err,ok;
char *messages[10];
LSURFuncs *lsurFunc;
LWLSURID script;
double lsur_num;
void *vars[1];
lsurFunc = (*global)(LWLSUR_GLOBAL,GFUSE_TRANSIENT);
script = (*lsurFunc->compile)(ui_script,messages,10);
The Universal Requester mechanism will compile the provided script code, and
return an opaque pointer that represents the compiled code. If there were
problems with your script code, any messages generated during the compile will
be placed into the provided receptical. If they exist, these messages should
be processed and freed afterward:
...
for(x = 0,err = 0;x < 10;x++)
{
if(!messages[x]) break;
if(!strncmp(messages[x],"e#",2))
{
++err;
(*msgFuncs->error)(&messages[x][2],"");
}
free(messages[x]);
}
if(err) return(AFUNC_OK);
...
Messages generated will be prefixed with a meta-code that indicates their
severity. Informational messages will be prefixed by "i#", warning messages by
"w#", and errors by "e#". If errors occurred during the compile, you should
gracefully exit (the returned script pointer will be NULL in any case).
The Universal Requester mechanism takes care of making sure your initial values
are where they should be, as well as seeing that the resulting values are returned
to you. In order to accomplish this, however, there are some design requirements
that must be adhered to.
1. controls must be initialized with variables in order to have data exchange
occur between the C plug-in and the LScript code.
2. variables used for data exchange must be prefixed with the letters "lsur_"
(see the above code example)
3. a call to getvalue() must be made on a specific variable in order to retrieve
the resulting control value for that specific variable back into the appropriate
receptical in the C plug-in
A list of (void *) are provided to the Universal Requester mechanism in order to
provide both initial values and a location to receive the result. Each (void *)
should point to a variable type appropriate to the control with which it is
associated. For instance, a ctlnumber() pointer should point to a (double) value.
...
lsur_num = 34.54;
vars[0] = (void *)&lsur_num;
ok = (*lsurFunc->post)(script,vars);
...
When the requester is dismissed, any variables that have had an explicit getvalue()
call assigned to them will be automtically updated in the C plug-in.
...
if(ok)
{
// user pressed "Ok", and values have been updated
...
}
...
Values can be changed again and the requester re-posted as many times as necessary.
When you are through with your requester, it should be passed to the release
function to free up the memory it consumes.
...
ok = (*lsurFunc->post)(script,vars);
(*lsurFunc->release)(script);
if(ok)
{
...
Any control type supported by LScript can be used in the requester, however, only
the following control types are supported for data exchange:
(char *)
ctlstring()
ctltext()
ctlfilename()
ctlimage()
ctlsurface()
ctlfont()
(integer)
ctlinteger()
ctlchoice()
ctlpopup()
ctlcheckbox()
ctlslider()
ctlminislider()
ctlstate()
(double)
ctlnumber()
ctldistance()
ctlpercent()
ctlangle()
(double[3])
ctlvector()
ctlcolor()
ctlrgb()
ctlhsv()
(LWItemID)
ctlallitems()
ctlmeshitems()
ctlboneitems()
ctlcameraitems()
ctllightitems()
(LWImageID)
ctlimageitems()
(LWChannelID)
ctlchannel()
|
The header file required to use this mechanism (lwlcore.h) can be
found in the LightWave 7.5b SDK distribution. Also included in the
SDK is a sample project, called "lsur", that illustrates the usage
of the LScript Universal Requester mechanism.
|
|
|
A keys() method can be applied to an associative array to extract all keys contained
within the array. This allows a script to access all data elements contained in the
associative array in a linear fashion.
|
|
A contains() methods is now available for integral data types that will, given a data
type and value, search through indexable types (arrays, strings, etc.) to determine if
that type and value exists. It returns a Boolean true/false value to indicate the
presence or absence, respectively, of the provided value.
...
str = "Now is the time";
info(str.contains("is the")); // displays true (1)
info(str.contains("Bob")); // displays false (0)
...
...
t = @15.87,"Blowfish",<1,9,0.5>@;
info(t.contains(<1,9,0.5>)); // displays true (1)
info(t.contains(15.87)); // displays true (1)
info(t.contains("Blow")); // displays false (0)
...
|
|
LScripts now have additional modes of saving that can be selected using the new @save
pragma. The original mode stores the full path name of the script into the scene or
object file. This mode is the default, and does not have to be explicitly selected.
Scripts can also be saved in relative mode. This saves only the name of the script
in the scene or object file. Upon reload, a script with that name should exist in the
default LScript directory \NewTek\LScripts. This is handy for situations like batch
rendering, allowing scripts to be flexibly relocated.
Lastly, scripts can be directly embedded within, and carried along with, the scene or
object file. This ensures that the script will always be available no matter where the
file goes, or when or where it is reloaded.
@save original
@save relative
@save embedded
To employ these settings, the script must first be activated from a disc file. Subsequent
saving and loading of scene or object files will permanently maintain these settings.
Scripts must be deactivated and the scene or object re-saved to disable the storage mode.
|
Debugging should not be attempted with embedded scripts.
Debug your scripts first before you activate this saving
mode.
|
|
|
A new control type called ctlviewport() is available to script requesters. This control
is similar to ctlinfo(), however, it functions as a viewport into a larger canvass area.
The canvass can be much larger than the viewport window, and can be navigated using
included vertical and horizontal scroll bars.
The arguments to ctlviewport() are identical to that of ctlinfo(), save for an additional
callback that reports the dimensions of the virtual canvass. This size function will always
be called immediately before the redraw function, so you can dynamically resize the canvass
to fit the situation.
c1 = ctlviewport(200,200,"vp_redraw","vp_size");
This size callback should return the width and height of the canvass upon which the
viewport (whose size is set in the initial function call) will traverse. The size function
could, for instance, return a fixed size or it could calculate the bounding area of objects
positioned upon the canvass. It accepts the control identifier to which the dimensions should
apply.
vp_size: ctl
{
return(800,600);
}
Drawing on the canvass should be performed without regard to viewport size. Your drawing
function should behave as though the user can see the entire canvass at once. It accepts the
control identifier for which drawing functions will apply.
vp_redraw: ctl
{
drawbox(<80,80,80>,0,0,800,600);
drawbox(<200,200,200>,50,50,20,20);
drawbox(<0,200,0>,750,450,20,20);
}
In addition, the Control Object Agent class now exports two new data members called xoffset
and yoffset. These data members are currently a constant zero (0) for all types except for
the viewport control. The values in these data members contain the current X (left) and Y
(top) offsets of the control's viewport. These values can be used to accurately calculate
things such as the virtual location of mouse events on the canvass.
reqmousedown: mouse_x, mouse_y, ctrl
{
x = mouse_x - ctrl.x + ctrl.xoffset;
y = mouse_y - ctrl.y + ctrl.yoffset;
...
}
Or they can be assigned values to position the viewport at a specific location on the
virtual canvass. The range of allowable values runs from zero (0) to
(canvass_width - viewport_width) on the horizontal, and zero (0) to
(canvass_height - viewport_height) on the vertical. LScript will automatically clamp
assigned values to these ranges if you exceed them.
|
|
The Requester mechanism now provides four new primitive drawing functions, drawcircle(),
drawelipse(), drawfillcircle() and drawfillelipse(). As their names imply, the first two draw
unfilled circular shapes, while the latter two draw filled circular shapes, on the panel or in
any other valid drawing region (e.g., ctlviewport()).
drawcircle() takes four arguments, being (1) color, (2) X center point, (3) Y center point,
and (4) radius. drawfillcircle() takes five, (1) border color, (2) fill color, (3) X center
point, (4) Y center point, and (5) radius. All numeric values are interpreted as integers.
drawelipse() takes five arguments, being (1) color, (2) X center point, (3) Y center point,
(4) X radius, and (5) Y radius. drawfillelipse() takes six, (1) border color, (2) fill color,
(3) X center point, (4) Y center point, (5) X radius, and (6) Y radius. All numeric values are
interpreted as integers.
|
|
A Requester panel's position can now be set and queried using the new reqposition() command.
The command takes two optional arguments that specify the screen X and Y position for the
panel. These values can be set at anytime between reqbegin() and reqend(). If the panel is
open on the screen when the call is made, the panel's position is immediately altered.
Whether called with or without arguments, reqposition() will return the current position of the
panel at the time the call is made. This makes it possible for a script to perform its own
between-runs management of the panel's position on the screen (LScript does this automatically
since v2.5, but there are only a limited number of panels it will remember).
generic
{
reqbegin("Position Test");
...
req_x = recall("req_x",0);
req_y = recall("req_y",0);
reqposition(req_x,req_y);
...
return if !reqpost();
...
(x,y) = reqposition();
store("req_x",x);
store("req_y",y);
reqend();
...
}
Because reqposition() will immediately update an open panel, on-screen positioning can be
performed in real time:
req_x,req_y;
generic
{
reqbegin("Position Test");
...
return if !reqpost("idle",500);
...
reqend();
...
}
idle
{
++req_x;
++req_y;
reqposition(req_x,req_y);
}
|
|
New I/O functions are available to the I/O Object Agent passed to the save() and load()
pre-defined script functions. These new methods provide finer granularity when dealing
with numeric data types in OBJECT I/O mode.
readDouble() will pull in a double-sized numeric value (typically eight bytes) from the
source file. writeDouble() will store a numeric value of the same size. The existing
readNumber()/writeNumber() methods continue to perform their operations using the
float-sized numeric value.
readShort()/writeShort() will work with short-sized numeric values (typically two bytes).
The readInt()/writeInt() functions continue to work with integer-sized values (typically
four bytes).
|
|
New File Object Agent methods are available that provide finer granularity when dealing
with integral numeric data types.
readDouble() will pull in a double-sized numeric value (typically eight bytes) from the
source file. writeDouble() will store a numeric value of the same size. The existing
readNumber()/writeNumber() methods will perform their operations using the
float-sized numeric value.
readShort()/writeShort() will work with short-sized numeric values (typically two bytes).
The readInt()/writeInt() functions continue to work with integer-sized values (typically
four bytes).
|
Please see the note in the Behavioral Changes section regarding
the new, optional argument that all File Object Agent binary-mode
methods accept for managing byte ordering.
|
|
|
The currently selected Weight, Texture or Morph vertex map can now be acquired in Modeler by
providing an index value of zero (0) to the VMap() constructor when specifying one of the three
vertex map types:
vmap = VMap(VMWEIGHT,0) || error("Select a Weight map so I have something to do!");
|
|
A new Layout function is available called visitnodes(). This function attempts to simplify
the process of iterating down through object parenting hierarchies.
The function requires two arguments. The first argument is an Object Agent reference
for an object type capable of containing children--Mesh, Light, Camera or Bone.
The second argument is a character string that identifies a UDF in the script that will be
called by LScript for each child object found in the hierarchy. The UDF must accept two
arguments, the parent Object Agent and the child Object Agent. Be aware that multiple calls
may be made with the same parent identity if that parent manages more than one child.
generic
{
visitnodes(Mesh("MasterObject"),"process_node");
}
process_node: parent, child
{
info(parent.name," -> ",child.name);
}
|
|
A new Layout Object Agent method called keyExists() can be used to identify all of an object's
channels that contain a keyframe at an indicated time index. Each channel that contains a
keyframe at the indicated time will be returned by the method.
generic
{
if((channels = Mesh("Null").keyExists(2.0)) != nil)
{
foreach(c,channels)
info("Null." + c.name);
}
}
|
|
A binary() function is now available that will convert integer values into their binary
equivalents in string form. The function takes an integer value, and an optional size
value (whose maximum on any platform is [sizeof(int) * 8] bits). The function will remove
leading zeros, unless an explict number of bits are indicated:
generic
{
info(binary(32)); // displays "100000"
info(binary(32,32)); // displays "00000000000000000000000000100000"
info(binary(130,8)); // displays "10000010"
info(binary(130,10)); // displays "0010000010"
}
|
|
A new Object Agent class has been defined in LScript called a Glyph. This class is a container
for color images, whose intended purpose is to act as color icons that can be drawn into display
contexts such as the Requester redraw, ctlinfo() and ctlviewport().
Glyphs can be constructed from a disc file by providing the filename as argument to the Glyph
constructor. Alternately, the name of an embedded binary block can also be specified as the
source of the image data:
...
cursor_img = Glyph(cursorGlyph);
...
@data cursorGlyph 500
000 000 002 000 000 000 000 000 000 000 000 000 012 000 012 000 024 000 080 080
...
A 'nil' is returned if the glyph construction fails for some reason.
The Glyph Object Agent currently exports no public methods. The following public data members
are available:
w the width of the glyph image (read-only)
h the height of the glyph image (read-only)
pixel[col,row] array of pixel color data for the glyph image
(write-only in default mode, read-write in dual-mode)
Once constructed, the glyph can be drawn into display contexts using the new drawglyph()
function. This function takes the Glyph Object Agent, along with the X and Y position
within the context where the glyph should be drawn:
...
// draw the cursor glyph
drawglyph(cursor_img,
cursor_pos.x - integer(cursor_img.w / 2),
cursor_pos.y - integer(cursor_img.h / 2));
...
Two additional arguments, both optional, can be provided to the Glyph() constructor. By default,
Glyphs are generated in a way that allows them to be drawn to the display context with the
utmost speed. What is traded for such drawing speed is the ability to directly access individual
pixels in the image. The second argument you can provide to the Glyph() constructor is a
Boolean flag that tells LScript that you'll need pixel-based access to the image data in the
Glyph (dual-mode). You'll need to specify this mode, for instance, when you plan to overlay the
Glyph onto Image Filter data (Image Filter data is not a valid display context, so the high-speed
form of the Glyph cannot be directly drawn onto it).
The third optional argument is a transparency color mask to be used when drawing the Glyph.
Because the use of such a mask requires per-pixel access to the image data, specifying a
transparency mask automatically enables this mode in the Glyph object.
Because Glyph image data can be of any type supported by any Image Loader plug-in active in
the host application (see notes regarding this in the Behavioral Changes section), you may
need to specify a file-type hint when you embed the image data into your script via a binary
block. By default, LScript will append the extension ".tga" to image data in a binary block
before attempting to process it. Sometimes this will work with non-Targa image data, and
sometimes it won't. Your file-type hint should take the form of the appropriate file
extension, and be appended to the name of the binary block, separated by an underscore
character.
@data cursorGlyph_jpg 500
000 000 002 000 000 000 000 000 000 000 000 000 012 000 012 000 024 000 080 080
080 080 080 080 080 080 080 080 080 080 080 080 080 080 080 080 080 080 080 080
...
085 069 086 073 083 073 079 078 045 088 070 073 076 069 046 000
@end
|
|
Variables local to a user-defined function can now be made static (i.e., their values persist
across invocations of the function) by prefacing the name of the variable with the characters
"st_".
generic
{
for(x = 0;x < 5;x++)
docount();
}
docount
{
if(!st_value)
st_value = 0;
info(++st_value);
}
|
|
Five new Command Sequence functions have been added to Modeler LScript:
revert([<filename>])
Causes the current object to revert to the mesh stored in the specified disc
file. If no file is provided, LScript attempts to revert using the object file's
current filename (of course, if the file hasn't been saved yet, an error will
result).
selectvmap(<type>,<name>)
Selects the specified VMap type and name for editing. The <type> can only be
one of Morph, Spot, Weight, Subpatch weight or Texture UV. These types can be
specified using the same type values provided to the VMap() Object Agent
Constructor.
meshedit(<name>)
Invokes a MeshEdit plug-in of the specified name.
smoothscale(<distance>)
Performs a Smooth Scale operation on the selected mesh, offsetting the
mesh by the specified <distance>.
changepart(<name>)
(Re)assigns the part name of the currently selected polygons.
|
|
The Mesh Object Agent exports two new public methods:
layerName(<layernum>)
Returns the assigned name for the specified layer of the object. If the layer
has yet to be assigned a name, then the method returns 'nil'.
layerVisible(<layernum>)
Returns a Boolean true or false to indicate the visible state of the indicated
layer.
|
|
New character classification methods have been added to the system. Each of these methods maps
directly to their ANSI C counterparts, and can be applied to integer values, or string values
where only the first character in the string will be regarded.
None of the methods accept arguments, and each returns a Boolean true/false value.
isPrint()
Test the character for printability.
isAlpha()
Test the character for membership in the alphabetic class (i.e., a-z or A-Z).
isAlnum()
Test the character for membership in the alpha-numeric class.
isAscii()
Test the character for membership in the ASCII character set.
isCntrl()
Test the character for membership in the control code character set.
isDigit()
Test the character for membership in the numeric character set (i.e., 0-9).
isPunct()
Test the character for membership in the punctuation character set
(i.e., any printable character that is not a space character, or a character
for which isAlnum() returns true).
isSpace()
Test the character as whitespace (i.e., a space character, or character in the
range 0x09–0x0D).
isUpper()
Test the character for membership in the upper-case alphabetic character set.
isLower()
Test the character for membership in the lower-case alphabetic character set.
isXDigit()
Test the character for membership in the hexidecimal character set (i.e.,
one of "0123456789ABCDEF").
|
|
The existing LScript log() function calculates the natural logarithm (base-e) of the provided
value. This can be a bit misleading for those seeking base-10 functionality, so a new function
has been added, log10(), to address this.
generic
{
x = log(23);
y = log10(23);
z = log(23) / log(10); // same as log10(23)
}
|
|
The LScript language has a new power operator, "^^". This operator can be used directly in the
the language as a substitute for the pow() function.
t = 5^^2; // 25
i = 10;
info(i ^^ 3); // displays 1000
|
|
Image Filter LScripts can use a new function called overlayglyph() to blend a Glyph Object
Agent onto the image data cache. This function takes a Glyph Object Agent reference and an
X and Y offset position where the Glyph will be stamped onto the image cache. An optional
fourth argument allows the Glyph image to be composited onto the image cache with a
transparency (alpha) value, ranging from 0.0, which renders the Glyph without transparency
(the default value), to 1.0, which renders the Glyph with 100% transparency (the Glyph will
not be visible).
bug;
create
{
bug = Glyph(vt4000,true);
setdesc("Bug");
}
process: width, height, frame, starttime, endtime
{
overlayglyph(bug,1,1);
overlayglyph(bug,1,height - bug.h,0.25);
overlayglyph(bug,width - bug.w,height - bug.h,0.5);
overlayglyph(bug,width - bug.w,1,0.75);
overlayglyph(bug,(width - bug.w) / 2,(height - bug.h) / 2,0.25);
}
@data vt4000 67800
000 000 002 000 000 000 000 000 000 000 000 000 188 000 120 000 024 000 026 026
026 025 025 025 025 025 025 025 025 025 026 026 026 026 026 026 025 025 025 025
...
000 000 000 000 000 000 084 082 085 069 086 073 083 073 079 078 045 088 070 073
076 069 046 000
@end
The result:
|
|
Channel Object Agents now provide a data member called parent that contains the LightWave
Object Agent to whom the channel belongs.
|
|
The Scene Object Agent's generalopts[] array now has a seventh [7] array element that
indicates the current state of the "Auto Key" button on the interface -- Boolean true
for "on", and Boolean false for "off".
|
|
The Scene Object Agent now provides the following additional data members:
alertlevel
indicates the state of the Alert Level setting in Layout. Will be one of
ALERT_BEGINNER, ALERT_INTERMEDIATE or ALERT_EXPERT.
boxthreshold
an integer value indicating the current bounding-box threshold setting.
autokeycreate
indicates the state of the Alert Key Create setting in Layout. Will be
one of AKC_OFF, AKC_MODIFIED or AKC_ALL.
numthreads
the number of threads that will be spawned during rendering.
animfilename
the name of the currently selected animation file. 'nil' if none.
rgbprefix
the name of the RGB file-saving prefix. 'nil' if none.
alphaprefix
the name of the Alpha channel file-saving prefix. 'nil' if none.
|
|
LightWave Object Agents now export an array called axislocks[]. This array contains
nine elements, where each triplet corresponds to the object's Position, Rotation and
Scaling channels. Each triplet element corresponds to the appropriate axis for the
transformational category, and is a Boolean value that indicates the lock status of
that particular channel/axis element (true == locked).
|
|
An Icon Object Agent has been added to LScript. This object type is designed to construct
and house a bitmapped pattern of pixels. These pattern of pixels represent a complete user-
defined text character (or "dingbat"). Icon characters are active only during an active
Requester panel.
The maximum dimension of each character is 16 pixels wide by 14 tall. Characters are defined
by placing character strings into an array. The width of each character string should not
exceed the maximum width, while the number of strings in each array should not exceed the
maximum height. In each character string a period character ('.') indicates a zero-pixel
value (off), while any non-period character will represent a one-pixel value (on). Each array
is provided to the Icon() constructor for construction and storage of the monochrome character
image.
folder_icon = @ "..1111..........",
".1....111111....",
".1..........1...",
".1..........1...",
".1...1111111111.",
".1..1..........1",
".1.1..........1.",
".11..........1..",
".111111111111..."
@;
eyes_icon = @ "................",
"................",
"...mmm...mmm....",
"......m.m.......",
"....mm...mm.....",
"...m..m.m..m....",
"..m.mm.m.mm.m...",
"..m.m..m.m..m...",
"..m....m....m...",
"...m..m.m..m....",
"....mm...mm.....",
"................",
"................"
@;
@define FOLDER 1
@define EYES 2
generic
{
icon[FOLDER] = Icon(folder_icon);
icon[EYES] = Icon(eyes_icon);
reqbegin("Testing Icons");
c1 = ctlbutton("Open File " + icon[FOLDER],75,"bfunc1");
c2 = ctlstring(icon[EYES].asStr() + " Browse","testing");
reqpost();
}
bfunc1
{
...
}
Icons can then be embedded in any character string that will be processed and displayed by
LScript (button or control label text, listbox entries, etc.).
|
|
In addition to SCHEMA, the Custom Object flags() function can now also return the
following values:
VPINDEX
indicates that the value in the view data member should correspond to
the viewport number instead of its type.
NODEPTH
causes drawing of the object to occur in front of all other OpenGL elements,
regardless of Z position.
|
|
The getdir() command now recognizes the SCRIPTSDIR constant, or the "scripts" string, and
will return a path that points to the NewTek\LScripts installation directory on the local
system.
|
|
A getsep() function has been added that will return the platform-specific path separator
character.
...
info(getsep()); // displays "\", "/" or ":" depending on the operating system
...
|
|
The Displacement Access Object Agent, provided to the process() function of Displacement
LScripts, now exports a point data member. This data member holds a Point Object Agent
for the mesh point currently being processed.
|
|
LScript now provides support for hexidecimal-formatted numbers. These numbers are prefixed by
the "0x" character sequence, and can contain 1-8 hexidecimal digits (A-F, a-f, 0-9).
...
t = 5 * 0xa0; // equivalent to 5 * 160
...
In addition, the integer() function has been enhanced to recognize and process hexidecimal
numbers in string form.
...
t = integer("0x0a"); // t will hold 10
t = integer("Now is the 0xF000 time"); // t will hold 61440
...
|
|
LScript now provides support for binary-formatted numbers. These numbers are prefixed by the
"0b" character sequence, and can contain 1-32 binary digits (0 or 1).
...
t = 0b1001; // t holds 9
...
In addition, the integer() function has been enhanced to recognize and process binary
numbers in string form.
...
t = integer("0b110"); // t will hold 6
t = integer("Now is the 0b10000 time"); // t will hold 16
...
|
|
A new function called lscriptVersion() returns information about the version of the LScript
system that is executing the script. It returns four elements in this order: a string
representation of the LScript version (identical to that displayed by LScript in the title
bar of the script-select file dialog); the major component of the version as an integer;
the minor component of the version as an integer; the patch level of the version as an
integer.
|
|
The Layout LScript Compiler provides a new mode for generating compiled scripts. This new
compiled type is a "library", and is intended to be a collection of functions (potentially
unrelated) that are not associated with any single plug-in architecture. Once compiled, this
"library" script can be used by any LScript through the use of the library command.
Functions defined within the "library" file can be referenced from a script as though they
were built into LScript.
@version 2.6
@warnings
@script generic
// the 'functions.lsc' library contains the gimmeStringFrom() function
library "functions.lsc"; // no path, so file should be in \NewTek\LScripts
generic
{
t = 104;
info(gimmeStringFrom(t));
}
|
|
A new callback named reqkeyboard() can be defined to intercept keyboard activity on the active
Requester panel. This function takes a single argument which represents the raw key pressed.
It should return a Boolean false or true value indicating that the key should or should not be
further processed by the system, respectively.
@version 2.6
@warnings
@script generic
generic
{
reqbegin("Testing reqkeyboard()");
c1 = ctlstring("String","value");
if(reqpost())
info("You pressed Ok");
else
info("You pressed Cancel");
reqend();
}
reqkeyboard: key
{
if(key == 13) // enter
{
reqabort(true);
return(true);
}
else if(key == 27) // escape
{
reqabort();
return(true);
}
return(false);
}
The following pre-defined constants have been added to the environment in order to help process
key events:
REQKB_F1 REQKB_KB0 REQKB_KP0
REQKB_F2 REQKB_KB1 REQKB_KP1
REQKB_F3 REQKB_KB2 REQKB_KP2
REQKB_F4 REQKB_KB3 REQKB_KP3
REQKB_F5 REQKB_KB4 REQKB_KP4
REQKB_F6 REQKB_KB5 REQKB_KP5
REQKB_F7 REQKB_KB6 REQKB_KP6
REQKB_F8 REQKB_KB7 REQKB_KP7
REQKB_F9 REQKB_KB8 REQKB_KP8
REQKB_F10 REQKB_KB9 REQKB_KP9
REQKB_F11
REQKB_F12 REQKB_ALT REQKB_RETURN
REQKB_SHIFT REQKB_INSERT
REQKB_LEFT REQKB_CTRL REQKB_HOME
REQKB_RIGHT REQKB_END
REQKB_UP REQKB_DELETE REQKB_PAGEUP
REQKB_DOWN REQKB_HELP REQKB_PAGEDOWN
|
|
A new indexOf() method can be applied to string, linear array and binary block data types. This
method can be used to locate data within these indexable types. The method returns the index
where the specified data is found. If it is not found, then a value of zero (0) is returned.
In the case of character strings, the provided search value is treated as a displayable character:
...
s = "val1:15:3.14";
ndx = s.indexOf(':'); // returns 5
...
For linear arrays, the value provided must match an element in both type and value in order
to be considered a successful match. Not all data types are supported for searching.
Searches through binary data will treat the provided integer value as an unsigned character,
and should be in the range 0 to 255.
By default, searches begin at the initial index offset of one (1). You can specify a beginning
offset other than one by providing the integer offset before the search value.
...
s = "val1:15:3.14";
ndx = s.indexOf(':'); // returns 5
ndx = s.indexOf(ndx + 1,':'); // returns 8
...
|
|
The Surface Object Agent's getValue() method now has a companion method called setValue(). By
providing the channel name and an appropriate value, the value of the Surface's channel can be
altered.
...
(obj) = Scene().getSelect();
(firstsrf) = Surface(obj);
srf = Surface(firstsrf);
srf.setValue(SURFCOLR,<0,255,255>);
translucency = srf.getValue(SURFTRNL);
srf.setValue(SURFTRNL,translucency * 2);
...
All channels supported by getValue() can be altered using setValue() except for those involving
Image Object Agents.
|
|
The LScript pre-processor recognizes a new compile-time pragma named @sequence. This pragma
allows you to define a collection of names whose values are sequential increments. This pragma
type is similar to the C enum function.
A collection of sequence names is enclosed with open and close braces:
...
@sequence { ... }
...
Names in the collection are separated from one another by commas:
...
@sequence { VIEWPORT_CTL, COPY_CTL, PASTE_CTL }
...
Like lines of binary data, entries in the sequence collection can span multiple lines:
...
@sequence { VIEWPORT_CTL,
COPY_CTL,
PASTE_CTL }
...
By default, sequences begin at one (1) and increment by one thereafter. That is, in the example
above, VIEWPORT_CTL would have the value 1, COPY_CTL would equate to 2, and so on. The sequence
value can be overridden at any point by assigning a new sequence value to a collection entry:
...
@sequence { VIEWPORT_CTL,
COPY_CTL = 5,
PASTE_CTL }
...
In this case, VIEWPORT_CTL would still have the value of 1, but COPY_CTL would have the value
5 and PASTE_CTL would be assigned the value 6.
An increment value can also be specified by separating the sequence value from the new increment
value using a colon:
...
@sequence { VIEWPORT_CTL = 1:2,
COPY_CTL,
PASTE_CTL }
...
With this code, VIEWPORT_CTL would still have the value of 1, but COPY_CTL would have the value
3 and PASTE_CTL would equate to 5.
Once declared, you can use these sequence entries anyplace in your script you would otherwise
use a @define'd value.
|
|
The ctlbutton() function now accepts an optional fourth parameter that constitutes an argument
list that will be passed to the button's designated callback function. This argument list is
wrapped in quotation marks (i.e., passed as a string), and contains one or more argument values
each separated by a comma.
...
reqbegin("Testing");
c1 = ctlbutton("press me",70,"press_me","10,r1,r2");
reqpost();
...
The arguments indicated can be of a constant value (numeric or character string, with the
latter enclosed in double quotation marks), or they can be variable name references that
are either global or local to the function that invoked ctlbutton().
r1 = "bob";
generic
{
r2 = "hood";
reqbegin("Testing");
c1 = ctlbutton("press me",70,"press_me","10,r1,r2");
reqpost();
reqend();
}
press_me: arg1, arg2, arg3
{
info(arg1," ",arg2," ",arg3);
}
|
|
LScript's execution mechanism has been re-engineered to remove all global contexts.
A script's context is now passed from function to function as is the standard for LightWave
plug-ins.
|
|
Due to the redesign of LScript's execution mechanism, the interface for User-Defined
Object Agents and DLL functions has been altered to include an opaque context pointer
in the LSFunc structure. This opaque pointer must be included in all calls to LScirpt
functions defined within that structure. The interface version has been increased
as a result to 1.4, and all new Object Agent or DLL development must return this
value to LScript to ensure the correct structure pointer is provided to callbacks.
Existing binary Object Agent or DLL files should continue to function with LScript at
the previous (1.3) interface version, although it is highly recommended that the
Object Agent code be updated for the v1.4 interface, if possible. The v1.3 interface
is no longer governed by the LScript memory manager.
|
The new LScript header file can be found in the include directory
of the LightWave 7.5b SDK distribution, and is now called
"lwlscript.h".
|
|
|
The LScript Debugger's variable watch system has been redesigned. The current function's
arguments and local variables are now automatically displayed in the watch window as long
as the function is active. As each new function is entered (or returned to), it's variables
replace those of the previous function. This behavior is more consistent with popular
debuggers. Informational displays have also been greatly enhanced.
Global variables are not automatically added to the watch window. In order to add global
variables to the watch, you must now highlight the variable name in the script by double-
clicking with the left mouse button, and then select "Add Watch" from the Debug menu (or
press the F3) key. If the selected text matches the name of a global variable in the script,
it will be added to the watch window and will remain in the watch window as you move in and
out of functions.
|
|
The Modeler new() command, upon success, now returns a Mesh Object Agent for the new
object created.
main
{
m1 = Mesh(0);
info(m1.id);
m2 = new();
if(!m2.isInt())
info(m2.id);
}
|
|
The Mesh() constructor now returns 'nil' for an index value that is out of range instead
of generating an error message and halting execution of the script.
|
|
LScript now automatically updates any persistent Object Agent references (i.e., stored in
variables or arrays anywhere in the script) with new object id's whenever they are
altered by Layout. This action occurs transparently, with no script intervention required.
It can result in some disconcerting behavior in your script unless you program with an
awareness that it can occur. For example, a script that stores Mesh Object Agents in an
array for processing might look like the following:
...
curObj = Mesh();
while(curObj)
{
objList[++x] = curObj;
curObj = curObj.next();
}
...
Later in the script, a particular object whose Agent is stored in the array is cleared
from the Layout scene using the ClearSelected() Command Sequence function:
...
objList[2].select();
ClearSelected();
...
When ClearSelected() is called, Layout removes the selected object from the scene. This
action typically causes a chain reaction in the current scene that alters all the internal
identifiers of the remaining objects. This event is now handled by LScript transparently.
However, you can see the result by looking at the array contents before the deletion:
and then after:
Notice that it looks as though the array itself has been altered by the change in the
scene. In actual fact, the underlying object identifiers of each Mesh Object Agent
have been updated, and their (new) corresponding object names now appear (in this case,
in the debugger watch window).
The fifth element in the array, which referenced the "(5)" Null object in the scene, now
identifies itself as "(none)". This is an indication that the object identifier it
contains is no longer valid in the current scene.
You should be aware of actions in your script that might generate such behaviors if you
have stored Object Agents of this type. From the example above, if you are deleting
objects from the scene based upon Object Agents stored in an array, you need to avoid
order dependency in the code that processes the array.
|
|
The Mouse functions now take a single Object Agent argument that wraps all available parameters
into a single package. This Object Agent exports the following data members:
ctl the Control Object Agent involved in the event ('nil' if none)
x X position of the event
y Y position of the event
button which mouse button triggered the event; 1=LMB, 2=MMB, 3=RMB
count the click count; 1=single-click, 2=double-click
keys[3] indicates key active modifiers; [1]=CTRL, [2]=SHIFT, [3]=ALT
The Object Agent currently exports no public methods.
...
reqmousemove: md
{
if(md.ctl)
{
vp_x = md.x - md.ctl.x + md.ctl.xoffset;
...
|
This change will cause problems for compiled LScripts that use the
old form of the mouse-handling functions. These scripts must be
updated and recompiled in order to function correctly with
this release of LScript.
|
|
|
The File Object Agent methods that deal with binary file modes now accept an optional Boolean
argument that indicates whether or not the read numeric value should have its byte ordering
swapped. By default, byte ordering will remain as it was read in from the file. Passing a
Boolean true will cause the byte ordering to be swapped before the value is returned.
|
|
The constant LINUX has been added to the environment, and will be returned by functions like
platform(). It can also be tested for using the pre-processor's conditional build @if system.
Any tests against this value that are true indicate that the script is running under the Linux
version of Screamernet (i.e., runningUnder() is guaranteed to return SCREAMERNET).
|
|
The pre-processor now performs multi-pass processing on the script in order to deal with
situations such as pragma directives appearing in multi-line comments:
/*
@define FOO 100
@autoerror
*/
|
|
Image-loading activities, such as those performed by ctlimage() or Glyph(), now channel through
any Image I/O plug-ins that might be active in the host application (Layout or Modeler). This
means that a much broader range of image file formats can now be processed besides just Targa.
|
|
The ctlimage() function now returns a 'nil' value if the attempt to load an indicated image file
fails. This will usually be an indication that the required ImageLoader plug-in has not been
installed into the application (an error message will still be displayed to the user if the
indicated image file simply doesn't exist). Scripts using non-Targa image files should check
this return value to ensure that the control was properly created.
|
|
The ChannelGroup() constructor now accepts two ChannelGroup Object Agents as arguments. Passing
one will return the first sub-group found under the specified channel group, however, two are
needed in order to iterate through all sub-groups found under a specified channel group. The
second ChannelGroup Object Agent is considered the "current" channel, and any sub-group defined
following it will be returned (or 'nil', if no further sub-groups exist).
|
|
The setvalue() function now first attempts to match a list value for ctlpopup() controls if a
string value is provided.
|
|
In order to be able to process discontinuous UV values, several of the VMap Object Agent's
methods have had their argument lists augmented.
isMapped(<point>[,<polygon>])
isMapped() now accepts an optional second argument which should be the
polygon for which the discontinuous UV values for the indicated point
should be checked.
getValue(<point>[,<polygon>][,<index>])
getValue() processes a second argument that indicates the polygon for
which discontinuous UV values should be retrieved. an <index> value can
also be specified to limit the retrieval to a specific value index.
setValue(<point>,<value>|<array>[,<polygon>][,<index>]) (MODELER ONLY)
a <polygon> can now be included in the setValue() argument list to allow
values to be assigned to a polygon's per-vertex (discontinuous) UV.
|
|
The loadimage() and clearimage() functions are now global, and can be used in either Layout or
Modeler.
|
|
The Mesh(), Camera(), Light() and Image() constructors have had their scanning code enhanced.
When an object name is provided, these constructors will match the first object found with that
name, regardless of alphabetic case. However, if two or more objects of that type exist in the
system with the same name, then one must match the name provided exactly in order for a sucessful
match to occur.
For example, an object called "Cow.lwo" is loaded into the application. The following code will
successfully match that object:
...
obj = Mesh("cow");
...
However, subsequently an object called "COW.lwo" is loaded, leaving "Cow" and "COW" in the
application. The previous code would fail (returning 'nil'), and must be altered to
unambiguously match one of the loaded objects:
...
obj = Mesh("Cow");
...
Object names returned to the script by the application will contain their respective case
settings, and so should always match the correct objects when used.
|
|
All pragma directives must now begin in the first column of the row in order to be
recognized. This is to remove confusion when an initblock token ('@') appears
as the first character on the line (at a column other than the first).
|
|
The ctlslider() function now accepts an optional fifth integer argument that can
be used to specify the absolute width of the slider component of the control. This
width is independent of the range of the slider itself.
|
|
The LScript Debugger's watch and message windows can now be interactively resized. By clicking
and dragging in the empty area just above either of these windows, you can resize the viewable
area to within some predefined limits.
|
|
The count() method can now be provided a character argument when applied to string-type
objects. When provided, the number of occurances of that character will be returned
to the caller as an integer.
...
s = "1:2:5:38";
info(s.count(':')); // displays 3
...
|
|
The asStr() method can now be applied to linear arrays. Supported data types will be
concatenated into a single string value. Elements of 'nil' value are ignored. You can
provide an optional character value that will be used to separate values added to the
string.
...
a[1] = "val1";
a[2] = 15;
a[3] = nil;
a[4] = 3.14;
info(a.asStr(':')); // displays "val1:15:3.14"
...
|
|
The CommandInput() function has been enabled for use in Modeler LScripts. It can be used
to invoke any CommandSequence functions specific to Modeler or common to both applications
that have not specifically been addressed within LScript.
...
CommandInput("Surf_SetWindowPos 100 50");
...
You should continue to use any available LScript-specific functions that map to CommandSequence
functions to provide argument type and value checking within your script.
|
|
The compiler now correctly recognizes and processes numeric values in scientific
notation without the need for trailing decimal values.
...
val = 2e2;
...
|
|
Due to the re-design of the execution mechanism, Procedural Texture LScript's can now
function properly when rendering is performed with multiple threads.
|
|
If the Mesh(0) constructor call was made on an unsaved object, it would return an
Agent for an object in the workspace that had been saved to disc already.
|
|
The Mesh(0) call was activating code that caused invalid indexing to occur under
Layout. When problems arose, they most often manifested as the incorrect object
being proxied.
|
|
The requpdate() function was not refreshing the panel when no arguments were
provided.
|
|
The setvalue() function was not correctly accepting empty string values.
|
|
Functions that did not return a value as expected could wreak havoc with LScript's
internal stack, causing a crash if they were used directly in comparisons, e.g.:
if(NotDone() == true)
...
NotDone
{
if(x == 0)
return(true);
// nothing returned on this path...
}
|
|
The server() method contained an inverted state test that prevented it from returning
anything but 'nil'.
|
|
The Modeler makecone() command was incorrectly converting floating-point arguments
into integers.
|
|
ctlinfo() controls were not being correctly rendered when they were attached to tab
pages.
|
|
SelectItem() was not properly processing bone name references.
|
|
Pre- and post-increment and pre- and post-decrement operators were not functioning
properly when applied directly to array elements.
|
|
Pragma directives inside comments were not being properly ignored by the pre-processor.
|
|
The setvalue() and getvalue() functions were not working properly with Tab controls.
|
|
The foreach() operator would not process any Object Agent type except Mesh.
|
|
The foreach() operator would not recognize Layout Object Agents in an array
provided for processing.
|
|
The filecopy() function contained a nasty bug that would destroy the contents of
the source file.
|
|
A rare case could occur with the foreach() operator where the variable used for the
iteration could retain a memory pointer that was subsequently reused by LScript's
memory manager for assignment to another variable. This situation could lead to a
crash when a function's local memory was reclaimed by the garbage collector -- the
cross-link situation would clear two variables when one was released, leaving the
second in an undefined state when it too was reclaimed.
|
|
Several constants defining the type of a Light were missing from the environment.
|
|
The points[] data member of the Polygon Object Agent was not being correctly bound
to its object type, and as a result, was inaccessible.
|
|
The measurements of the getWorldRotation() method were not being correctly converted
into degrees before return to the script.
|
|
The ShadowColor() function did not have the correct number of arguments defined.
|
|
When a whole number was used to initialized a ctlangle() control, the control value
would only increase regardless of which direction the scroller was dragged.
|
|
A memory overrun could occur in the Requester's panel position mechanism when all
available slots were filled. Panel positions are aged, with the oldest being
replaced by the current Requester, but the actual position in the list was not being
used. This overrun could manifest, among other ways, as a crash of the application
when the mouse pointer entered the Requester panel.
|
|
A control event ocurring in a modal Requester that had spawned another modal
Requester could cause LScript to become confused as to which was the currently
active panel. This typically manifests as the child panel being inaccessible,
and crashes possible with mouse activity.
|
|
The Scene fogColor() method was assigning all color values to the vector X element.
|
|
The ctlchannel() code had a subtle problem that prevented it from correctly
locating the specified initial channel in the listbox. This left things in
an unstable state, leading to crashing on subsequent invocations.
|
|
File line counting was not accurate when the last line did not contain a newline
sequence.
|
|
Queue Object Agents were not being properly reclaimed by LScript's garbage collector,
potentially leading to unsocial behavior (crash or lockup).
|
|
The split() function would cause a memory overrun whenever the drive component of
the provided path was loinger than about eight characters. Since PC drive designators
are almost always only two characters, this problem manifested more readily on the
Mac.
|
|
Several Command Sequence functions (like TargetItem() and ParentItem()) failed to consider
bones as valid targets.
|
|
Corrected a problem with setting listbox selections using the setvalue() function.
|
|
Corrected a problem with listbox updates and the requpdate() function.
|
|
Ownership of a Particle System Object Agent was not explicity identified in the system,
leading to destruction of the Object Agent (and to the underlying particle system) when
a variable that had attached to it was reclaimed by the garbage collector.
|
|
The meshedit() function was calling the SelectVMap command.
|
|
Requester separators were not erasing properly.
|
|
The ctlactive() function was not handling all elements of a compound control.
|
|
The @insert mechanism was not functioning correctly using the standard C file handling
functions. The pre-processor has been redesigned to process inserts in memory instead.
|
|
The LScript debugger was not capturing script messages correctly.
|
|
The LScript debugger was crashing upon exit due to some poor handling of the watch and
message window entries.
|
|
The Requester mouse functions were not covering the entire client area of the panel
when the mode was non-modal.
|
|
The LScript configuration module, responsible for managing data from functions like
store() and recall(), contained some potential ambiguity problems in its use of the
C strncmp() function when scanning for keys. This potential problem only affected
non-Windows platforms.
|
|
The internal mechanism responsible for duplication of an active script (engaged
in cases where you clone an item with a script enabled, for instance) was based on
some fairly archaic code. The means by which it performed the copy operation would
often leave the original script at risk of destruction, and would never really
activate the script on the new item.
The new mechanism will correctly activate the source script on the target item. It
will also copy certain global values from the original script into the corresponding
values in the new activation. Due to their complexity, certain data types, such as
Binary Blocks and internal Object Agents, are not duplicated in the target script.
The copy of values occurs only after the script is activated on the duplicated
object, and its create() function has successfully completed. This may have some odd
effects on your script, most obviously where the setdesc() function is concerned.
If you call setdesc() in your create() function, the duplicated script may end up
displaying values to the user that are not valid after the value copy has completed.
In order to combat this problem, LScript will look for a pre-defined function called
cloned() in the duplicated script. This function, if it exists, will be invoked by
LScript immediately following the duplication of global values from the original
script. The cloned() function takes no aguments, and should return no values.
Activities involving data changes within your script should be centralized within this
function. For instance, you could place a single call to setdesc() in this function,
and then invoke the function whereever appropriate from within your script:
...
create
{
...
cloned(); // after initial operational values are established
}
cloned
{
// data values have changed...
setdesc("...");
}
options
{
...
cloned(); // after user has changed operational values
}
...
|
|
The setvalue() function was not completely simulating user interaction with a control,
so not all defined callbacks were being invoked when a control's value was changed
programmatically.
|
|
Vector and distance controls were not evenly sizing their input fields when modified
using ctlposition(). Each now allocates the specified control width, less the
width of the control's label, evenly among their three input fields. In order to ensure
their integrity, the widths of each are now clamped when they fall below a pre-defined
minimum.
|
|
Usage of the previewstart, previewend, and previewstep data members while running under
Screamernet would cause a crash. These values, associated with an interface that doesn't
exist under the network renderer, are now mapped to renderstart, renderend, and renderstep
under Screamernet.
|
|
The LightWave LCore subsystem (which houses, among other things, LScript) has a new
interface mechanism that allows LScript to be embedded within applications that link
to it (currently, only internal LightWave applications can take advantage of this).
The LSIDE Editor is the first client to use the new Embedded LScript mechanism of
LCore. A new option under the "Tools" menu called "Macro..." provides an interface
to the management system of the Editor macros. Selecting this menu entry opens
a window that can be used to manage Editor macros. Macro files have the file
extension "els".
A third pop-up menu has been added to the Editor's on the top-right side of the
interface. It contains currently loaded macros, and is used for execution.
The Editor supports two kinds of macros, run-once or key-based. Run-once macros are much
like Generic scripts in LightWave. They execute once when invoked, and complete their
processing when they exit. Key-based macros (hereafter referred to as "filter" macros)
are similar to other LightWave scripts, such as Master or Motion, in that they sit idle
in the background when activated until either called upon to process a keystroke, or
explicitly deactivated.
Because the Editor's macro system is hosted by LScript, all non-LightWave-specific
functionality offered by LScript is also available to any application using Embedded
LScript. This extends not only to language features, but also to certain generic built-
in functions.
However, an application employing Embedded LScript can define its own set of context-
specific functions for use in its scripts. Below is a complete list of the context
functions defined by the LSIDE Editor.
<doc> newDoc([<filename>])
This function creates a new document in the editor. If a valid
filename is provided, then that file will be loaded into the new
document. Otherwise, and empty document is generated.
<doc> currentDoc([<doc>])
A handle to the current document is returned by this function.
If a handle is provided as an argument, then that document will
become the focus in the editor.
<doc> nextDoc(<doc>)
This function will return a handle to the document in the system
that follows the provided document handle (based on load order).
saveDoc(<doc>[,<filename>])
This function will return a handle to the document in the system
that follows the provided document handle (based on load order).
<integer> lineCount(<doc>)
Returns the number of the lines in the provided document handle.
<string> getLine(<doc>,<line>)
Returns the content of the indicated line number in the specified
document handle.
<color[]> getColor(<doc>,<line>)
Returns the color representation of indicated line number in the
specified document handle. The returned value is an array of RGB
color values in vector form.
addLine(<doc>,<string>[,<after>])
Adds the provided string text to the indicated document handle.
If the optional line number is included, then the line will be
added after that line in the document. Otherwise, the line will
be appended to the end of the document.
deleteLine(<doc>,<line>)
Removes the indicated line number from the specified document
handle.
deleteSelection(<doc>)
Removes any currently selected text in the specified document
handle.
replaceLine(<doc>,<line>,<string>)
Replaces the contents of the indicated line number with the
provided text.
replaceColor(<doc>,<line>,<color[]>)
Replaces the color contents of the indicated line number with
the provided array of color vectors.
markLine(<doc>,<line>)
Alters the representation of the document in the editor to
place marker to the left of the indicated line number. This
is identical in effect to the "Mark All Matches" setting of
the Search dialog.
<Boolean> isDirty(<doc>)
Allows the script to check the indicated document handle to
see if it has been modified (i.e., is in need of saving).
<type> docType(<doc>[,<type>])
Returns the type of the document handle. It will be one of
DOC_SCRIPT, DOC_CSOURCE, DOC_CHEADER, or DOC_OTHER.
Additionally, you can provide a type designation to alter the
type of the document. (Type designation is largely important
for syntax hightlighting.)
<string> docName(<doc>[,<fullpath>])
Returns the name of the indicated document. If the document
has no name (i.e, it has not yet been saved to disc), 'nil'
will be returned. You can also retrieve the full path name
of the document if you provide a Boolean true as the second
argument.
highlightSyntax(<doc>)
Activates syntax highlighting for the specified document.
(<row>,<col>) getCursor(<doc>)
Returns the cursor's current row and column position in the
specified document.
setCursor(<doc>,<row>,<col>)
Positions the cursor at the specified row and column in the
specified document.
<Boolean> selection(<doc>)
Queries the specified document to see if it has an active text
selection.
(<row>,<col>) getSelect(<doc>)
Returns the selection's current row and column position. When
a selection is active, its range is increased or decreased by
movement of the cursor. Thus, the values returned by this
function are the "anchor point" of the selection.
(<start>,<end>) getLineSelect(<doc>,<line>)
Returns the starting and ending column of the portion of the
indicated line that is included in the document's current
selection. This range can encompass the entire line, or just
a portion depending upon the position of the cursor and
selection anchor.
setSelect(<doc>,<row>,<col>)
Establishes the row/column position of the selection anchor
point in the indicated document.
<Boolean> selected(<doc>,<line>)
Queries indicated line in the specified document to see if it
is included (whether wholly or in part) in the document's current
selection.
<integer> countChar(<doc>,<char>[,<include>])
Scans the indicated document, counting the occurances of the
provided character. If the optional include argument is a
Boolean true, then character strings (i.e., sequences of
characters enclosed in quotation marks) are also scanned and
counted.
message(<string>)
Allows the script to display a text message in the message area
of the editor's interface.
<Boolean> inString(<doc>,<row>,<col>)
Indicates whether or not the specified row and column position in
the document falls within a character string (i.e., a sequence of
characters enclosed in quotation marks).
<Boolean> overwrite(<doc>[,<overwrite>])
Returns the read-only status of the indicated document, where a
Boolean true indicated read-write. The read-only status of the
document can be set if you provide a Boolean false as an optional
argument.
<string[]> funcNames(<doc>)
Returns the names of the functions that currently exist in the
specified document. The document must be of type DOC_SCRIPT and
functions must have been defined, or 'nil' is returned.
<Boolean> funcIsCollapsed(<doc>,<name>)
Returns the collapse status of the named function in the specified
document. A Boolean true indicates a collapsed state.
toggleCollapse(<doc>,<name>)
Expands or collapses the function body identified by the named
function in the specified document. Use funcIsCollapsed() to check
the function state before calling this funciton.
<integer> funcLine(<doc>,<name>)
Returns the line number of the named function in the specified
document. If the named function does not exist, then 'nil' is
returned.
The following functions are available only to filter macros:
replaceKey(<key>)
Substitutes the provided key value for the one currently being
processed. All subsequent key filters will receive this
replacement key value when they are invoked instead of the
original. This new key will also be the value passed on to
the editor, if indicated.
All macro types have a central point of entry called "macro". This is where execution of
the Editor macro begins, and, in the case of run-once macros, terminates when the macro()
function completes.
macro
{
...
}
Filter macros provide an additional user-defined function, called filter(), that serves
two purposes. First, its presence identifies the macro as a key-based filter. Second,
it acts like a LightWave LScript flags() function and returns one or more characters
for which it should be activated. For this latter functionality, the filter() function
can return a combination of character strings and integer values that will map to
the required key values:
filter
{
return("\ta",13); // trap tabs, lower-case 'a', and the Return key
}
The filter() function will be invoked by the Editor's macro system each time the
macro is activated. This can occur when the macro is first loaded at startup (if
it was active during your last session), or when you explicitly activate the macro
from the interface. For this reason, it serves as a good location to initialize
the state of the macro, if needed.
filter
{
pastPartials = nil; // reset for a new run...
return("\ta",13); // trap tabs, lower-case 'a', and the Return key
}
The macro() function of a filter macro can also accept one or two optional arguments which
represent the active document and the key to be processed. In filter macros where only a
single key is being trapped, this second argument is unnecessary. And, because the currentDoc()
function will return a handle to the active document, getting it in the argument list is
also redundant. However, in cases where more than one key is being intercepted, or in the
case where a filter macro is trapping all printable characters, these arguments can be useful
(for determining the key that caused the event in the former case, and for execution speed
in the latter). The key argument provided is the integer value of the event key.
filter
{
pastPartials = nil; // reset for a new run...
return("\ta",13); // trap tabs, lower-case 'a', and the Return key
}
macro: doc, key
{
switch(key)
{
case '\t': // tab
...
break;
case 'a':
...
break;
case 13: // Return
...
break;
}
}
Several LScript pragmas can be used by scripts excuted by Embedded LScript. For instance,
the @name pragma can (and must) be present in an Editor macro, and is used to set the name
of the macro in the list on the user interface.
@name Sort Ascending
macro
{
...
}
Any other LScript pragma not having to do directly with LightWave (@fpdepth, @define,
@strict, etc.) can also be present in an Editor (Embedded LScript) macro.
Here are some example macros that were created during the development of the Editor's
macro sytem. Some are practical, and some are useful only as examples of how to use
some of the provided context functions:
Name Type Description
------------------ -------------- --------------------------------------------
autosave.els filter saves the current document after a specified
number of keystrokes
a_to_A.els filter uses the replaceKey() function to capatilize
all typed lower-case 'a' characters
cf_template.els run-once simple script that creates a new document and
places a Channel Filter template into it
changecase.els run-once alters the case of the characters in the document.
adheres to any current selection. employs the
LScript requester mechanism.
color_e.els run-once changes the color of all the 'e' or 'E' characters
on the current line
disablecode.els run-once places a single-line comment operator (//) at
the start of every line in the current selection
enablecode.els run-once removes any single-line comment operators from
the start of every line in the selection
keycomplete.els filter completes the keyword from a partial entry when
the tab key is pressed
reformat.els run-once re-formats a script to make it more readable
smartindent.els filter automates code-based indentation in a smart
fashion
sort.els run-once sorts selected document lines in ascending order
|
|
Document text can now be scrolled using the mouse wheel on mice that provide them. In
addition, the wheel provides acceleration scrolling. Shorter times between individual
wheel clicks will scroll more lines.
|
|
File-open dialogs in the Editor are now multiple-select.
|