Download Strata 3D CX 5 Tryout Download Strata Foto 3D Tryout Download Strata Live 3D Tryout

Meson User Manual

Overview

"Meson" is the name of a suite of connected technologies which allow interactive applications with both 2D and 3D elements to be developed quickly, and with a very small execution footprint. Like "Java" the name denotes a language, an object model of predefined classes, and a runtime execution environment.

The ordinary deployment method of a Meson application is in an applet on a web page. The following example shows a typical use case:

<html><body>
<applet code='com.kaon.meson.MesonApplet' archive='mesonApplet.jar,rasterGluon.jar,sceneGluon.jar' width=400 height=300>
<param name='meson' value='
Applet.Primary.fill="336699";
Applet.Primary.image="/images/productDemo/splash.jpg";
Meson.gluon("com.kaon.meson.raster.RasterGluon");
Data.Primary.url="/apps/productDemo/program.jar";
'>
</applet>
</body></html>

In this example, a short program is given right in the HTML file, using the meson applet parameter. This program uses the trick of giving an attribute value over multiple lines, in order to improve readability. Note, however, that the HTML processor strips out the line feeds before passing the parameter to the applet, so the applet receives this program as one very long line. Therefore, each line ends with a ; to break the statements up for the parser. This program sets the background color of the applet (used until an image appears), then sets the initial image in the applet using a URL relative to this page. Next it loads the Java code used for 2D (raster) operations, and then creates a data source to fetch the application program. This program would display its own progress meter, and load other Java code to extend the functionality into the 3D space.

Note that there is no way to express the ' (apostrophe) character in a HTML parameter value. Therefore, this character is not required in the Meson language. If you need to include ' in a program on a web page, the unicode version \u0027 can be used.

Developing a Meson program using only a browser to debug can be difficult. For this reason, Meson includes a console application called "blackboard" which executes program files, and has a command-line interface into which expressions can be typed. In this way, it is similar to a LISP development environment, where debugging and programming are performed with the same tool. In the context of the blackboard application, the above program would be this:

/* Create the Primary applet window 400x300 */
Meson.newApplet(["Primary",400,300])
/* The rest is the same, except there is no need for trailing ; on each line */
Applet.Primary.fill="336699"
Applet.Primary.image="/images/productDemo/splash.jpg"
Meson.gluon("com.kaon.meson.raster.RasterGluon")
Data.Primary.url="/apps/productDemo/program.jar"

To run the blackboard application with a command line interface, open a command window, and cd to the folder where Live 3D is installed. Then type the following: jre/bin/java -mx96M -jar blackboard.jar optionally followed by the names of text files containing Meson program statements. To run the blackboard program non-interactively, just drag a program text file onto the Blackboard.exe launcher icon.

The blackboard application adds a few items to the Meson environment:

  • Meson.newApplet takes an array with up to 5 elements as its argument. First is the name of the applet, which can be prepended with a * to request an applet window with no title bar or close button. Then width and height, followed optionally by left and top screen coordinates.
  • Meson.exit takes a single number argument, causing the blackboard application to terminate with that exit code.
  • The attribute javaWindow is added to the Applet object, which can then be manipulated using Java reflection.
  • The attribute windowClosed is added to the Applet object, with the default value {Meson.exit(0)}. This can be changed by the application, as needed.

Conceptual Framework

The heart of a Meson environment is the blackboard. This is a common place where all data is stored. Each piece of data on the blackboard (each "attribute") has a name and a value. For example, Meson.clock ::= 5.3 is a way of expressing that the datum called "Meson.clock" has the value "5.3". The power in the Meson language comes from the ability to put expressions into the blackboard, which get their values by performing operations on other attributes in the blackboard. For example, Image.Blue.x ::= Image.Yellow.mouseX+50 says that the value of the attribute Image.Blue.x should always be 50 larger than the current value of the attribute Image.Yellow.mouseX. These two examples are expressed in the Meson language as follows:

Meson.clock=5.3
Image.Blue.x={Image.Yellow.mouseX+50}

The Meson.clock example is called an immediate expression, whereas the Image.Blue.x example is a deferred expression. When an expression references an attribute on the blackboard which is defined by a deferred expression, that expression is evaluated. In the semantics of Java, a deferred expression is like a method, whereas an immediate expression is like an instance variable. For almost all cases, deferred expression can fully describe the dynamic state of the sytem. However, for the few cases where this is not true, the Meson runtime provides the concept of a Trigger. A trigger combines some sort of test, with an expression to evaluate under conditions described by the test. There are several variations of Trigger, to detect "transition to true" conditions, "value changed" conditions, and "value might have changed" conditions. Triggers are only evaluated when the attributes in their test are assigned new values. In the case of deferred expression, the Trigger wll be tested when any attribute used in that expression is assigned a new value. In general, there are two ways to express most relationships between attributes:

Procedural
/* Re-center the toolbar when the display width changes using a Trigger */
ChangeTrigger.ToolCenter.test={Display.Primary.width}
ChangeTrigger.ToolCenter.exec={Image.Toolbar.x=Display.Primary/2}
Declarative
/* Define the toolbar to always be centered */
Image.Toolbar.x={Display.Primary.width/2}

When a choice like this exists, do not use the Trigger. The latter expression is more concise, easier to debug, and more efficient than the former expression. The temptation will probably be to use the former method, because that is how it would be done in a procedural language like Java or Basic. But Meson is a declarative language, not a procedural one. A Trigger should be used only when there is no way to express the relationship in a declarative manner, as shown in the following example:

/* Show the pressed state when the mouse is pressed (Declarative) */
Area.Button1.state={Area.Button1.press?"press":"off"}
/* Increment a counter on each press (Procedural) */
Trigger.Button1.test={Area.Button1.press}
Trigger.Button1.exec={counter=counter+1}

The blackboard uses a smart cache to minimize the runtime cost of using deferred expressions. For example, if Image.Toolbar.x is defined as follows:

Image.Toolbar.x={Display.Primary.width/2}

the first time anything reads Image.Toolbar.x from the blackboard, the calculation will be performed. This value is cached, and every other blackboard value which contributed to its calculation (just Display.Primary.width in this case), is tagged with the cache dependency. If Display.Primary.width changes, then the cached value of Image.Toolbar.x will be dropped. But until then, subsequent reads of this attribute will be essentially free. In a typical Meson application, about 90% of attribute fetches from the blackboard hit the cache.

The presence of the cache is generally transparent to the Meson programmer. However, there is one case which requires special care: programming by side effect. When an attribute on the blackboard is really being used as a procedure, callers must use care to reference it using procedure call semantics. For example:

/* Define a procedure to increment the counter */
increment={counter=counter+1}
/* Increment a counter on each press */
Trigger.Button1.test={Area.Button1.press}
Trigger.Button1.exec={increment()}

Note the use of parenthesis in the read of increment. This tells the cache system to evaluate the expression, regardless of whether a value might be cached.

The blackboard is augmented with a scratch data storage area, called the notebook. The notebook has pages, which can store attributes, much like the blackboard. The idea of the notebook is that it is a semi-private area where an expression can take notes without polluting the blackboard. For example:

distSquared={#dx=Applet.Primary.mouseX-cx;#dy=Applet.Primary.mouseY-cy;
                     #dx*#dx+#dy*#dy}

In this example, two notebook attributes (#dx and #dy) are used to store temporary values. Reading and writing attributes in the notebook is more efficient than working on attributes on the blackboard, because notebook attributes have two restrictions: notebook attributes cannot be tested in a Trigger, and notebook attributes cannot be objects (for example, #Image.Foo.x does not create an object of class Image, whereas Image.Foo.x would implicitly create such an object). Also, notebook attributes are not cached.

An application uses attributes on the current page of the notebook with the # operator. It is also possible to use attributes on the next page of the notebook, using the ^ operator. This facility is provided as an argument passing mechanism -- when an attribute is referenced using function notation (for example, Meson.sin(3.14)), the notebook page is advanced. This way each function can safely write any attribute without concern for trashing someone else's notes.

squareSum={#dx*#dx + #dy*#dy}
distSquared={squareSum(^dx=Applet.Primary.mouseX-cx;
                     ^dy=Applet.Primary.mouseY-cy)}

The remainder of this document fully describes the Meson language and object model.


Syntax

Meson programs are written in a line-oriented declarative language. A typical line of a Meson program looks like this:

attribute=value

Attributes can be simple names, or they can be fully qualified object members. For example:

/* Assign 5 to x */
x=5
/* Assign 5 to the x attribute in object Toolbar, of class Image */
Image.Toolbar.x=5

Each delcaration occurs on a single logical line. If the text is long, lines can be split by ending them with \ (similar to some BASIC interpreters). Unbalanced curly braces implicitly cause line continuation:

Image.Label.text="This is a very long string "+ \
                     "which has been split across lines."
Scene.3d.width={Display.Primary.Width-
                     Image.RightToolbar.Width}

Literal symbols include quoted strings (as with Javascript, the forms "string" and 'string' are both allowed, to ease embedding quote and apostrophe characters within strings), the special strings true and false, and any string of non-operator characters starting with any of the following: ._-0123456789 (period, underscore, minus sign, and digits). In essence, the quotes are optional when symbols start with these characters. Whether a symbol denotes a number depends on how it is used, not on what its starting character is. The symbols true and false are recognized by the parser and need not be quoted. Using quotes around a string allows the use of any special character, and also enables the use of escaping (\n for newline, \t for tab, \" for a quote, \' for an apostrophe, and \uXXXX for a unicode character). Note that the parser reads the text as UTF-8 encoded unicode, so using unicode escapes is only necessary if the text is being edited with a ASCII editor, like Notepad.

/* Examples of literal strings */
Style.Default.color=336699
Style.Default.color="336699"
Style.Default.color="FFFFFF"
black="ff000000"
text='He said, "Hello".'
text="It's my party..."
/* Example of attribute reference */
Style.Default.color=black
/* Example of attribute reference thru a literal string (functionally identical to previous line) */
Style.Default.color=@("black")
/* String using escaping character (newline) */
Image.Logo.text="Powered By\nwww.strata.com"
/* String using unicode escape for ° symbol */
Image.Temp.text={"Current Temp: " ~ temp ~ "\u00B0 C"}

There are two kinds of expressions which can be used on the right side of an assignment: immediate and deferred. An immediate expression is evaluated right away, whereas a deferred expression is like a little program which will run on demand:

Examples of immediate expressions.

/* Set the width of the main 3D window */
Scene.3d.width=300
/* Center the toolbar */
Image.Toolbar.anchor=_C
Image.Toolbar.x=Scene.3d.width/2

Examples of deferred expressions.

/* Set the width of the main 3D window to always match the primary display */
Scene.3d.width={Display.Primary.width}
/* Set the position of the toolbar to always be centered */
Image.Toolbar.x={Display.Primary.width/2}

Expressions can combine terms using a variety of operators:

  • * / %  Multiply, Divide, Remainder
  •  + -   Add, Subtract
  • ! & |  Not, And, Or (boolean operators)
  •  ∪ ∖   Union, Set Minus (array operators; ++ -- also accepted)
  •   ~    Concatenate (string operator)
  • ≈ < >  Equal to, Less Than, Greater Than (== is accepted in place of )
  • ≠ ≤ ≥  Not Equal to, Less or Equal, Greater or Equal (!= <= >= also accepted)
  •  ? :   Test (a?b:c means if (a==true) then b else c), the : clause is optional
  • @ # ^  Attribute Reference, Local Reference, Parameter Reference
  •   ¬    Dereference (-> also accepted)
  •   =    Assignment
  •  ; ,   Statement Separators
  •  { }   Deferred Expression
  •  ( )   Grouping/Function Operator
  •  [ ]   Array Operator
  •  « »   Prefix Section (<< and >> also accepted)

The following examples demonstrate some syntactic paradigms:

/* Set the state of an area, based on the current 3D mode */
Area.Measure.state={Scene.3d.mode=="rotate"?"on":"off"}
/* Use a local attribute for efficiency */
/* Notice that when multiple expressions appear in a row, the last is the value of the expression as a whole */
attr={#dx=(Image.Pop.x-Image.base.x); #dx * #dx}
/* Use a deferred expression as a function, passing argument thru a global */
/* Use the function in an immediate assignment to attr */
square={square.arg * square.arg}
attr=(square.arg=(Image.Pop.x-Image.base.x); square())
/* Use a deferred expression as a function, using the implicit argument #arg */
square={#arg * #arg}
attr=square(Image.Pop.x-Image.base.x)
/* Use a deferred expression as a function, using explicit arguments */
squareSum={#x*#x + #y*#y}
attr=squareSum(^x=Image.Pop.x-Image.base.x;^y=Image.Pop.y-Image.base.y)
/* Compute a value using recursion */
power={#exp==1?#base:(#base*power(^base=#base;^exp=#exp-1))}
Image.Expr.text="5^6=" ~ power(^base=5;^exp=6)
/* Same thing, but using tail recursion instead of a function call */
power={#exp==1?#base:(#exp=#exp-1;#base*power)}
/* Store the name of an object in a string, then get an attribute of that object */
theImage="Image.Main"
theX={@(theImage~.x)}
/* Same thing, but using dereference syntax */
theY={theImage->y}
/* Example of using + to join deferred expressions */
/* This is equivalent to (Meson.log("Hello");Meson.log("World")) */
hello={Meson.log("Hello")}
helloWorld=hello+{Meson.log("World")}
/* Example of using prefix sections */
Foo.Class<<
.bar=1 /* equivalent to Foo.Class.bar=1 */
.baz=2 /* equivalent to Foo.Class.baz=2 */
>>

Built-in Functions

The Meson interpreter defines a handful of built-in functions:

foreach(string elem, array in, deferred do) iterates over the elements in an array:

numbers=[one,two,three]
count={^c=0;foreach(^elem="i";^in=numbers;^do={#c=#c+1;@Meson.log(#c~" = "~#i)})}
/* Results:
meson> count
1.0 = one
2.0 = two
3.0 = three
 */

try(deferred exec, deferred catch) returns the value of the exec clause unless an exception is thrown, in which case the value of the catch clause is returned. When the catch clause is evaluated three additional local attributes are placed in the notebook: exception fully qualified Java class of the exception; message message member of the Java exception; javaException actual Java Exception object.

width="90%"
widthNum={try(^exec={width+0};^catch={
Meson.log("E: {"~#exception~"}");
Meson.log("M: {"~#message~"}");
Meson.log("J: {"~#javaException~"}");
-1})}
/* Results:
meson> widthNum
E: {com.kaon.meson.MesonException}
M: {Error converting "90%" to Number
90%
width
width+0}
J: {com.kaon.meson.MesonException: Error converting "90%" to Number
90%
width
width+0}
-1
 */

Meson.length(array arg) returns the number of elements in the array.

Meson.assert(boolean arg) throws an exception if the passed arg is not equal to "true":

a=5
b={Meson.assert(a==5); a}
c={b*b}
d={a=3}
e=d+c
/* Results: When the last line is exectued:
meson> e=d+c
input:5: e=d+c
Assertion Failed
ƒMeson.assert
_Meson.assert_
call _Meson.assert_ with ((a≈5))
(call _Meson.assert_ with ((a≈5)));@a
_b_
_b_*_b_
_c_
_d_+_c_
e=_d_+_c_
 */

Meson.throw(string arg) throws an exception

Meson.log(string arg) prints a string to the console

Meson.dump(string arg) dumps the blackboard contents to the console. Only blackboard items starting with the passed argument are dumped. Use Meson.dump("") for a full dump.

Meson.getMethod(string class, string method, array args) and Meson.callMethod(java.lang.reflect.Method method, array args) are used together to access Java methods:

/* Access the Java random number generator */
randMethod=Meson.getMethod(^class="java.lang.Math";^method="random";^args=[])
rand={Meson.callMethod(^method=randMethod;^args=[])}
Image.Foo.x={rand * Display.Primary.width}
/* Access the Java atan2 method (this is actually included in the Raster gluon) */
Meson.atan2Method=Meson.getMethod(^class="java.lang.Math"; \
                     ^method="atan2";^args=["double","double"])
Meson.atan2={Meson.callMethod(^method=Meson.atan2Method;^args=#arg)}
someAttr=Meson.atan2([1, 0.5])

Note that for non-static methods, the Java object to operate on should be passed as the first array element to Meson.callMethod but should not be declared in the array passed to Meson.getMethod. Use the built-in attribute null to pass a null pointer as an argument.

Meson.newInstance(string className) creates an instance of a Java class using the no-arguments constructor.

Meson.gluon(string arg) loads a Gluon to add more built-in functions:

/* Put splash.jpg into the applet, then load the Raster functions and show splash2.jpg */
Applet.Primary.image="splash.jpg"
Meson.gluon("com.kaon.meson.raster.RasterGluon")
Display.Primary.file="splash2.jpg"

Each bit of functionality in the Meson system is provided by a Gluon. A Gluon is a set of Java classes which extend the native capabilities of the Meson language. This document describes functions provided by the Raster and Scene Gluons.

Meson.showDocument(string applet, string url, string target) is used to request than an applet show an HTML page (url parameter) in a frame or window (target parameter).

Meson.showStatus(string applet, string status) is used to request than an applet show a message in the the status bar of the browser window.

Meson.jsEval(string javascript) is used to invoke an arbitrary javascript expression in the context of the web page that includes the applet. Note that the MAYSCRIPT attribute must be added to the applet tag on the HTML page if this method is used.

Meson.addContextMenu(string applet, string label) adds a label to the applet context menu. Calling this with the ^label="-" inserts a separator. When the user accesses an item on the context menu, this label value is placed in the applet's menuItem attribute.

/* Add a context menu item to open a web page */
Meson.addContextMenu(^applet="Applet.Primary", ^label="CNN")
Trigger.CNN.test={Applet.Primary.menuItem=="CNN"}
Trigger.CNN.exec={Meson.showDocument(^applet="Applet.Primary", ^url="http://cnn.com", target="_blank")}

Meson.unique generates a unique identifier, useful for creating helper objects.

/* This is a utility function to create a repeating timer */
/* for example, setInterval(^delay=1, ^exec={Meson.log(Meson.clock)}) */
/* It uses Meson.unique to generate a unique name for the timer */
setInterval={#t="Timer."~Meson.unique();#t->delay=#delay;#t->repeat=true;#t->exec=#exec;
                     @(#t->start);#t}

Meson.checkpoint captures the entire state of the blackboard into an attribute

Meson.restore(arg) restores the state of the blackboard to the passed checkpoint

/* Put checkpoint/restore on the context menu */
Meson.addContextMenu(^applet="Applet.Primary", ^label="Checkpoint")
Meson.addContextMenu(^applet="Applet.Primary", ^label="Restore")
ckpt=Meson.checkpoint()
Trigger.Checkpoint.test={Applet.Primary.menuItem=="Checkpoint"}
Trigger.Checkpoint.exec={ckpt=Meson.checkpoint()}
Trigger.Restore.test={Applet.Primary.menuItem=="Restore"}
Trigger.Restore.exec={ckpt=Meson.restore()}

Note that the checkpoint itself is not in the checkpointed blackboard, so restore returns the checkpoint, so that it can be stored into the restored blackboard. If the Restore trigger simply said Trigger.Restore.exec={Meson.restore()} then the attribute ckpt would disappear after restore, since it is restoring a blackboard which had no ckpt attribute on it.

Meson.setInterval(number delay, deferred exec) creates a repeating timer, similar to the JavaScript setInterval function

Meson.setCurrentDataSource(string arg) sets the default data source for images created between now and the next time this is called. This is used by the Data class of the Raster gluon to control defaulting when reading a meson program, and the data used by that program, from the same file. The argument should either be the name of a Data object (Meson.setCurrentDataSource(Data.myProg)) or a URL relative to the current document base (Meson.setCurrentDataSource("http:/data/")). Since this is set automatically by the Data object, it is unlikely an application will ever need to call this function.

Meson.clock holds the time since Meson initialization, in seconds.

Meson.frameStep holds the amount of time since the last tick, in seconds.

Meson.documentBase holds the URL of the applets using this blackboard.

Meson.displayDepth holds the bit depth (16 or 32) of the display on which the applet appears.

Meson.notebookPages holds the number of pages in the notebook (32, by default). An application can increase this limit if it needs to use recursive evaluations which are very deep.

clear black green silver lime gray olive white yellow maroon navy red blue purple teal fuchsia aqua are all predefined with their CSS-equivalent color values (clear has alpha channel of 0x00, all other have alpha of 0xff)

Meson.isMac is true on Mac OS (9 or X) platforms

Meson.language holds the two-letter code of the default user language as reported by the O/S (en, es, zh, etc...)


Object Models

Several classes are included in the the baseline Meson system: Trigger, ChangeTrigger, HairTrigger, Timer, Ticker, Applet, and GenericPeer. Applications create instances of these classes with the notation Class Name.Instance Name.attributes...=value. In other words, an instance of a class is created when one of the attributes of that instance is referenced.

Each class defines a set of attributes which have special meaning in instances of that class. The application may use custom attributes within the scope of an instance as well. The predefined attributes have types which the system expects to find when it parses them. These are:

  • string a string of unicode characters
  • integer a positive, negative, or 0 whole number
  • number an integer or floating point number (when this represents an integral values, such as pixels, floating point values will be rounded to the nearest integer)
  • color an ARGB color value specified as 4 or 8 hex digits, or an RGB color value specified as 3 or 6 hex digits (note that the character # used in HTML colors must be omitted, because # has special meaning)
  • enum a value from the specified list of choices
  • boolean true or false
  • array a set of values (generally, if a value of a different type is used where an array is expected, a one-element array will be created automatically)
  • attribute the name of an attribute or class instance
  • native a native Java object
  • deferred a deferred expression

Assignments which do not start with a class name create attributes in a global variable space. Assignments which start with a # create attributes on the current notebook page. Assignments which start with a ^ create attributes on the next notebook page, which will be the current notebook page of the next function invoked.

The defaults for a class can be overridden using the special object Class which acts as a template during instantiation. For example, to change the default for Images to use 16-bit color depth instead of 32-bit color depth, use Image.Class.depth=16. Note that this will not retroactively change existing instances. To implement retroactive changes to defaults, use deferred assignments: defaultImageDepth=32 and Image.Class.depth={defaultImageDepth}. In this example, images get {defaultImageDepth} as their depth attribute, so that a subsequent assignment defaultImageDepth=16 would flow through to the images.

Applications can create custom classes using the special member extends. For example, HotImage.extends="Image" creates a new class HotImage which extends Image. The application can then assign attributes to HotImage.Class which will become the defaults for HotImage objects. Note that if an attribute matches the name of an attribute in the superclass, then the subclass initializer sets the superclass attribute instead. For example, if HotImage.Class.layer=5, then when the object HotImage.Foo is created, the assignment Image.Foo.layer=5 will occur. In this example, HotImage.Foo.layer becomes a proxy to the underying attribute Image.Foo.layer, so reads and writes of either attribute actually change the one in the base class.

A class can extend multiple base classes. For example, Display.extends=["Applet","Image"]. The order in which base classes are listed is used to resolve conflicts. For example, both Applet and Image define the width attribute. Since Display extends Applet first, the default value of width comes from Applet, and the Display and Image versions of the object both proxy width from Applet:

A.extends=""
A.Class.a=1
A.Class.x=2
B.extends=""
B.Class.b=3
B.Class.x=4
C.extends=["A","B"]
C.Class.c=5
C.Class.a=6
/* Create a C called foo, and make sure it's b is 3 */
Meson.assert(C.foo.b==3)
/* First base class wins */
Meson.assert(C.foo.x==2)
/* Super class wins */
Meson.assert(C.foo.a==6)
Meson.assert(C.foo.x=9;(A.foo.x==9 & B.foo.x==9 & C.foo.x==9))

The $ character is substituted dynamically in class initialization with the name of the object being created. For example, HotImage.Class.x={HotSpot.$.x} implies that the object HotImage.Reset automatically get the attribute assignment HotImage.Reset.x={HotSpot.Reset.x}, allowing automatic linking between objects in the user-defined class HotImage and similarly named hotspots. Similarly, $$ substitutes the fully qualified name including the class and instance parts.

/* Load a localization table */
i18n.OK="Way!"
i18n.Cancel="No Way!"
/* Set up a class to conveniently set up text areas using translations */
I18NImage.extends="Image"
I18NImage.Class.text={i18n.$}
/* Create some images using translation. Note that the .text member is set automatically */
buttonPadding=5
I18NImage.OK.anchor=SE
I18NImage.OK.x={Image.Dialog.width/2 - buttonPadding}
I18NImage.OK.y={Image.Dialog.height - buttonPadding}
I18NImage.Cancel.anchor=SW
I18NImage.Cancel.x={Image.Dialog.width/2 + buttonPadding}
I18NImage.Cancel.y={Image.Dialog.height - buttonPadding}

A class can be given a special member new which is an expression evaluated when an instance is created, just after all the predefined Class attributes are set. This facility can be used to automatically create partner attributes or objects which go along with instances of a class.

/* Define a TipImage to be an image which auto-hides after 2 seconds */
TipImage.extends="I18NImage"
TipImage.Class.time=2
TipImage.new={ Timer.Hide$.delay=$$.time;
                     Timer.Hide$.exec={$$.layer=-1};
                     Trigger.Hide$.test={$$.layer>-1};
                     Trigger.Hide$.exec={Timer.Hide$.start()} }
TipImage.Class.anchor=_S
/* Create a tip image to go with an area called Reset */
TipImage.Reset.x=Area.Reset.x+Area.Reset.width/2
TipImage.Reset.y=Area.Reset.y
/* Define a SlowTipImage to be a TipImage with a longer delay */
SlowTipImage.extends="TipImage"
SlowTipImage.Class.time=5
/* The following line creates a SlowTipImage, but the time setting does not have the desired effect (see the explanation, below). */
SlowTipImage.Foo.time=1

The prior example demonstrates the order in which initialization of objects takes place when subclassing is being used:

  • superclass (recursively) members
  • subclass members
  • superclass (recursively) new
  • subclass new
  • instance members

In the example, the final assignment results in the following assignments (in this order) at run time:

/* I18NImage initializers */
Image.Foo.text={i18n.Foo}
/* TipImage initializers */
TipImage.Foo.time=2
Image.Foo.anchor=_S
/* SlowTipImage initializers */
TipImage.Foo.time=5
/* TipImage new */
Timer.HideFoo.delay=TipImage.Foo.time
/*  (evaluates to Timer.HideFoo.delay=5) */
Timer.HideFoo.tick={Image.Foo.layer=-1}
Trigger.HideFoo.test={Image.Foo.layer>-1}
Trigger.HideFoo.exec={Timer.HideFoo.start()}
/* Assignment statement */
TipImage.Foo.time=1

The final assignment has no effect, because the assignment to Timer.Hide$.delay was an immediate expression. In order for this example to have the intended results, a deferred expression should have been used:

TipImage.new={ Timer.Hide$.delay={TipImage.$.time};
Then the initialization would have been:
Timer.HideFoo.delay={TipImage.Foo.time}

which would respond to subsequent changes to the time member of TipImage objects.

The .new attribute is unique, in that each one in a class hierarchy has an opportunity to run during initialization. Contrast this with other attributes, in which the proxy substitution rules described above cause subclass members to merely replace superclass members at instantiation. Sometime it is desirable for the subclass to override an attribute (particularly one which holds a deferred expression), but keep access to the superclass definition as well. This can be accomplished by accessing the special Class instance member, and using the + operator to join deferred expressions together:

Foo.extends=""
Foo.Class.someMethod={Meson.log("$$ " ~ #arg)}
Bar.extends="Foo"
Bar.Class.access=0
Bar.Class.someMethod=Foo.Class.someMethod+{$$.access=$$.access+1}

Another case where + is used to join expressions is adding functionality to an already-defind method:

Foo.Class.new=Foo.Class.new+{Meson.log("Detected creation of object: $$")}

By convention, class and object names start with capital letters, while attributes start with lowercase letters. This language is case sensitive.


Basic Object Model

Class: Trigger

A trigger runs a deferred expression when the value of a test expression changes to true.

This example sets an attribute in response to a mouse press on the Area called Button

Trigger.Show.test={Area.Button.press}
Trigger.Show.exec={Image.PressedImage.layer=9}

This example sets an attribute in response to a mouse release on the Area called Button

Trigger.Hide.test={!Area.Button.press}
Trigger.Hide.exec={Image.PressedImage.layer=-1}
 test
An expression which should evaluate to true or false
Typedeferred
 exec
This expression is evaluated when the test transitions from false to true
Typedeferred

Class: ChangeTrigger    (Extends Trigger)

A change trigger runs a deferred expression when the value of a test expression changes.

This example increments a counter whenever an area changes state in any way

ChangeTrigger.StateCount.test={Area.Button.state}
ChangeTrigger.StateCount.exec={Area.Button.stateCounter=Area.Button.stateCounter+1}
 test
An expression which is evaluated
Typedeferred
 exec
This expression is evaluated when the test value changes
Typedeferred

Class: HairTrigger    (Extends Trigger)

A hair trigger runs a deferred expression when anything referenced in the test might have changed, regardless of whether the value of the test expression actually changed. Note that writing a value to the blackboard which is identical to the value already there will not fire a HairTrigger.

This example prints a message whenever the layer or alpha is modified

HairTrigger.DebugVis.test={Image.Foo.layer;Image.Foo.state}
HairTrigger.DebugVis.exec={Meson.dump(Image.Foo)}
 test
An expression
Typedeferred
 exec
This expression is evaluated whenever anything in the test might have changed
Typedeferred

Class: Timer

Timers are used to perform actions after a delay, or periodically.

This example displays a popup image for a hotspot when the mouse enters, and uses a timer to hide the hotspot 2.5 seconds after the mouse exits.

Timer.HidePort.exec={Image.portPopup.layer=-1}
Timer.HidePort.delay=2.5
/* Use a trigger to show the popup */
Trigger.SP1.test={HotSpot.Port.hover}
Trigger.SP1.exec={Image.portPopup.layer=9}
/* Use a trigger start the hide timer */
Trigger.SP2.test={!HotSpot.Port.hover}
Trigger.SP2.exec={Timer.hidePort.start()}
 delay
The delay between events generated by this timer (seconds).
Typenumber
Default0
 repeat
Controls whether the timer fires once, or periodically.
Typeboolean
Defaultfalse
 exec
This expression is evaluated when when the timer ticks.
Typedeferred
 start
Reading this attribute starts the timer.
RestrictionsUse function() semantics
 stop
Reading this attribute stops the timer without firing it.
RestrictionsUse function() semantics

Class: Ticker

Tickers are used to evaluate an expression every frame. An order member is present which can be used to control the order of execution of Tickers in the system.

 order
Tickers execute in increasing order, starting at 0. The order of execution for Tickers with the same order attribute is the order in which they were created. Setting the order to a value less than 0, such as -1, will prevent the ticker from ticking.
Typenumber
Default0
 exec
This expression is evaluated when when the Ticker ticks.
Typedeferred

Class: Applet

Applet objects represent applets on web pages. Applet is the only graphical class included in the base object model, in order to keep the initial footprint of Meson very small. Applications will typically use the Applet class only to display a splash logo. After loading the Raster gluon, the application will then use the Display class which extends the Applet class with image manipulation capabilities.

The name of an applet comes from it's mesonName property on the HTML page. If no name is given, the default Applet name is Primary. If the application uses multiple applets on the same Blackboard, names must be assigned explicitly.

 javaApplet
This holds the java.applet.Applet object for the applet.
Typenative
Default""
RestrictionsRead Only
 javaImage
This holds the java.awt.Image object used as the background of the applet. Initially, this is based on the image attribute, but when the Raster gluon is loaded, the Display class replaces it with a new image to reflect the dynamic state of the executing program.
Typenative
Default""
RestrictionsRead Only
 fill
The fill is used at Applet startup to control the background color.
Typecolor
Defaultfff
 image
The image attribute is a URL (relative to the document on which the applet is placed) of an image to show in the Applet while the remainder of the program is loading. Progressive JPG or Interlaced GIF images can be used to get immediate content onto the screen.
Typestring
Default""
 pleaseRepaint
When set to true, the applet will ask Java to initiate a repaint.
Typeboolean
Defaultfalse
 width
Width of the applet. This may change if the applet is in a resizable window, and uses percentage for its width attribute.
Typeinteger
Default0
RestrictionsRead Only
 height
Height of the applet. This may change if the applet is in a resizable window, and uses percentage for its height attribute.
Typeinteger
Default0
RestrictionsRead Only

Keyboard and mouse input is delivered into Applet attributes. In order to ensure Trigger objects fire correctly, the events are queued as they happen, so that if multiple events happen during a frame, the next frame will get all those events in order. For example, if the left mouse button is clicked, the press element will be set to true (causing Triggers watching for press to execute), and then to false (causing release Triggers to execute).

 mouseX
The X position of the mouse, measured from the left side of the applet. Note that browsers typically only deliver mouse coordinates when the applet has focus.
Typeinteger
Default-1
RestrictionsRead Only
 mouseY
The Y position of the mouse, measured from the top of the applet. Note that browsers typically only deliver mouse coordinates when the applet has focus.
Typeinteger
Default-1
RestrictionsRead Only
 press
True when the left mouse button is being pressed in the applet.
Typeboolean
Defaultfalse
RestrictionsRead Only
 shift
True when the Shift key is pressed and the applet has focus.
Typeboolean
Defaultfalse
RestrictionsRead Only
 ctrl
True when the Control key is pressed and the applet has focus.
Typeboolean
Defaultfalse
RestrictionsRead Only
 key
Holds the most recently typed key. Triggers which respond to keystrokes can set this back to "" after firing, to respond to mulitple presses in a row. For special keys, this holds the key name (Enter, Left, Right, Up, Down, Tab, Delete, Back). For all other keys, it holds the unicode letter.
Typestring
Default""

Class: GenericPeer

Generic Peer is extended by other objects which bear a very close relationship to objects implemented by Gluons in Java code. Their primary purpose is to provide a simple, consistent way for Meson programs to invoke methods on these native objects. Their use is entirely optional, as they merely wrap calls to built-in functions like Meson.getMethod and Meson.callMethod.

 javaClass
Specifies the fully-qualified Java class name of the native peer class.
Typestring
 javaObject
Holds the native object which is created in reponse to this object being referenced in the Meson program. Note that a no-arguments constructor is used by default, so a native class using this facility should use separate initializers (similar to the design pattern used in Applets and Servlets).
Typenative
 callMethod
Invokes a method on the native object. Arguments are as follows:
  • method: native method name as a string
  • types: array of argument types. For primitive types, use strings like float or long. For object types use the fully-qualified class name, such as java.lang.String. For array types, use the Java method signature conventions (for example, "[[F" for a two-dimensional array of float, or "[Ljava.lang.String;" for a one-dimensional array of strings.
  • args: array of arguments, which must correspond to the values passed in the types parameter. As explained above, use null for null parameters.
Typedeferred
 getMethod
Looks up a method of the native object. When a method is going to be called very frequently, it is a good idea to look it up once in advance and cache it, rather than looking it up over and over with callMethod. Arguments are as follows:
  • method: native method name as a string
  • types: array of argument types. For primitive types, use strings like float or long. For object types use the fully-qualified class name, such as java.lang.String. For array types, use the Java method signature conventions (for example, "[[F" for a two-dimensional array of float, or "[Ljava.lang.String;" for a one-dimensional array of strings.
Typedeferred

Raster Gluon

The Raster gluon adds several classes to Meson: Anim, Data, Image, Display, Area, and Style. It also adds several built-in functions.

Raster Built-in Functions

Meson.sin(number arg), Meson.cos(number arg), Meson.tan(number arg), Meson.atan(number arg), Meson.atan2(array arg), Meson.round(number arg), Meson.ceil(number arg), Meson.floor(number arg), Meson.ln(number arg) (natural log), Meson.exp(number arg) (natural exponent) provide access to the equivalent methods in java.lang.Math. For convenience, the attributes Meson.degToRad and Meson.radToDeg are also defined.

/* Create a ticker which updates the angle at frame rate */
Ticker.Dot.exec={currentAngle=currentAngle+Meson.frameStep*rateDegPerSec}
rateDegPerSec=360/60
/* Set the x,y location of an image to move around a circle */
Image.Dot.x={dotRadius * Meson.cos(currentAngle*Meson.degToRad)}
Image.Dot.y={dotRadius * Meson.sin(currentAngle*Meson.degToRad)}
/* Derive radius value from image parent width */
dotRadius={(Image.Dot.parent~.width)/2-Image.Dot.width}

Meson.formatFloat(number value, string format) returns the number formatted according to the user's regional numeric formatting conventions, as specified by the OS. The format specifier is of the form integerDigits[.decimalDigits]. That is, the if no decimal part is given, the value will be shown as an integer.

Raster Object Model

Class: Anim

Animation objects are used to set attributes to values over time. The animation uses a combination of linear interpolation and exponential smoothing, to allow values to change in a variety of ways.

This example shows how to use an Anim object to make a toolbar slide in when the mouse enters the area (like a desktop taskbar with auto-hide).

/* Define a rectangle on the toolbar to detect mouse hover. */
/* Default dimensions of the area match the Image size. */
Area.ShowToolbar.image="Image.Toolbar"
/* Create an animation to control the y coordinate of the image toolbar, */
/* changing it at a maximum rate of 10 pixels per second. */
Anim.ToolY.attr=["Image.Toolbar.y"]
Anim.ToolY.rate=10
Anim.ToolY.highPriority=true
/* Have the goal be 5 pixels, or toolbar height pixels, above the display bottom. */
Anim.ToolY.goal=[{Display.Primary.height-(Area.ShowToolbar.hover?Image.Toolbar.height:5)}]
 attr
The attributes which are controlled by this animation.
Typearray of attribute
 goal
The value to be assigned to each attr over time.
Typearray of number
 rate
The maximum rate (per second) at which to change the value. If this value is <0, the rate is not limited.
Typenumber
Default-1
 smooth
The exponential smoothing constant to apply when changing the value. A value of 0 changes instantly, whereas a value of 1 will never change. This parameter controls the amount of goal value to blend with the current value each time step, based on the equation weight=smoothtimeStepSeconds. Typical values are around 0.05.
Typenumber
Default0
 threshold
When an attribute value is this close to the goal (|goal-attribute|≤threshold) the attribute will be set to exactly the goal.
Typenumber
Default0.001
 enabled
The animation only operates when this attribute is true.
Typeboolean
Defaulttrue
 autoDisable
If this is set to true, the animation will set its own enabled attribute to false when the attribute value reaches the goal. This is used for "one shot" animations.
Typeboolean
Defaultfalse
 modulus
If modulus is non-zero, then the attribute will skip up or down an appropriate amount to never be more than half the modulus away from the goal. For example, when the attribute is an angular measure, a modulus of 360 will lead to the attribute following the shortest path around the circle to the goal.
Typenumber
Default0
 highPriority
A high-priority animation sets an internal flag in the applet context when it is running (i.e., when the attribute value is not the goal, and the animation is enabled). This flag is consulted by various low-priority tasks, such as 3D Scene anti-aliasing, to control sharing of CPU cycles. In a nutshell, a high-priority animation will be visually smoother than a normal priority one on a heavily loaded system. For animations with moving rasters, such as the toolbar animation in the above example, this will give a better appearance. For animations of alpha parameters, it is generally not necessary, as the user cannot see the subtle frame rate differences involved.
Typeboolean
Defaultfalse

Class: Data

Data objects represent a bundle of resources used by a Meson application. The data file referenced by this object is in the ZIP (JAR) format, and may contain an arbitrary mix of .txt files containing Meson programs, .jpg and .gif files used by those programs, 3D scene data including wavelet .kwl files and compressed binary data, and other ZIPs or JARs. The best compression is achieved by building a compressed JAR containing a single uncompressed JAR with the files. The resulting compression is much better than a simple compressed JAR.

 url
URL (relative to the page the applet is on) of the JAR file containing the data
Typestring
 state
State of the data file. Data starts in the _NEW state, immediate transitions to the _OPEN state where data is read, and transitions to the _CLOSED state when reading is complete. It may transition to the _FAILED state if any error occurs.
Typeenum 
_NEW, _OPEN, _CLOSED, _FAILED
RestrictionsRead Only
 errorMessage
When the state is _FAILED, this holds the error message
Typestring
RestrictionsRead Only
 contentLength
Contains the content length, as reported by the server. Note that this may be -1 if the server does not know the content length.
Typenumber
RestrictionsRead Only
 bytesRead
Contains a count of bytes read so far.
Typenumber
RestrictionsRead Only
 stall
Set this to true to temporarily stall reading the data.
Typeboolean
Defaultfalse
 fileList
Contains the list of files read from this data source so far.
Typearray
 imagePercentLoaded
If the data source contains wavelet-encoded images, this holds the percentage of image data which has been decoded so far.
Typenumber
Default100
 reset
When set to true, the file read will stop, and the state will transition back to _NEW. This will cause the file to immediately start loading again, unless you first set the url attribute to "".
Typeboolean
 parse
Indicates that the URL points to Meson code or a ZIP/JAR archive which should be parsed.
Typeboolean
Defaulttrue
 unparsed
When the parse attribute is false, the data pointed at by the URL will be read into a string and placed into this attribute.
Typestring

Class: Image

An image is a rectangular raster of pixels. There are three ways to create an image: from a file, by rendering text, or simply allocating a blank area.

 file
Create the image from the specified file. The file may be a GIF or JPG format image (PNG format is not supported in all browser environments, so it should be avoided). GIF files may use animation, although this should be avoided where possible for performance reasons (using a multi-state image and flipping thru the states will yield faster update rates). In cases where a continuous alpha channel is required (in contrast to the On/Off alpha of GIF transparency), two images may be given, separated by an @ symbol. The first file gives the color information, and the second gives alpha information. For example: Image.Toolbar.file="toolbar.jpg@toolbarMask.gif". The blue channel of the pixels in the GIF images are used as the alpha channel (in practice, a gray-scale GIF can be used, since the red and green channels are ignored). The color pixels may come from either a JPG or GIF format file, however, if GIF is used, it must not include transparency (specify transparency in the alpha channel file instead). Animation is not permitted in an alpha channel GIF.
Typestring
Example"top.jpg"
 text
Create the image by rendering the specified text. The background of the text comes from the buffer attribute. If no buffer color is given, the text will be on a transparent background.
Typestring
Example"Open Lid"
 tabDefault
Specifies the default spacing, in pixels, for tab stops (used when rendering text containing the \t character).
Typenumber
Default50
 tabStops
Specifies explicit tab stop locations, in pixels. Note that, as with word processing programs, the default tab spacing is used to the right of the last explicit tab stop.
Typearray
Default[]
 wrapWidth
Text can be auto-wrapped while being rendered, to ensure the resulting image does not exceed a certain width. This attribute controls that process. Note that spaces, tabs, language-specific rules (such as Japanese, where breaks between glyphs are allowed except in a few cases), and style-changes can result in breaks (the non-breaking-space unicode character \u00A0 can be used to insert a non-breaking space between words). If a single piece of unbreakable text is longer than will fit in the wrapWidth, then text wrapping will not be performed on that text. In this case, the width member could end up larger than wrapWidth, if set implicitly. If you assign a particular value to width then text which extends beyond this will be clipped.
Typenumber
Default0
 language
When using the wrapWidth attribute, this selects the language rules to use when determining how to break long lines at word boundaries.
Typestring
Default{Meson.language}
 country
When using the wrapWidth attribute, this selects the country-specific language rules to use when determining how to break long lines at word boundaries.
Typestring
Default""
 buffer
Create a buffer with the specified fill color
Typecolor
Example"FF336699"
 softEdge
Used together with a buffer, this softens the alpha channel all the way around the rectangular image by the specified number of pixels on each side.
Typenumber
Default0

Images can represented internally using 32-bit ARGB, or 16-bit YCrCb representation. In the 32-bit setting, alpha and the 3 color channels are represented by 8 bits each. In the 16-bit setting, each adjacent pair of pixels share a chominance value, and each has its own luminance. Both modes support a full 256 gray levels, but only the 32 bit mode supports alpha channels and the complete range of colors. For textures compressed with JPEG compression, there is nothing to be gained using 32-bit representation, because JPEG forces each pair of adjacent pixels to have the same chrominance.

 depth
Set the color depth to be used to represent this image
Typeenum 16, 32
Default32

Text images will always use font smoothing when the underlying Java implementation supports it. When it does not, font smoothing can be emulated to varying degrees of precision. The higher the degree, the longer it takes to render the text initially. Once the text is set, however, the speed of rendering is not impacted by smoothing.

 fontSmooth
Font anti-aliasing control. A value of 0 does no anti-aliasing, 1 does a little anti-aliasing, while value of 2 does maximum anti-aliasing. Note that text which changes frequently, such as the measuring distance, should use a value of 0 for best performance. This only controls the default anti-aliasing for an image. Individual text Styles can specify a different level of text anti-aliasing, which will take precedence over this setting.
Typeenum 0, 1, 2
Default2

An image can have multiple states, which are stacked vertically, with the first state on top, the next one below it, and so on. The version of an image which appears on the screen is the first state overlaid with other states as specified by Area objects within the image.

 states
Names the states represented within the image.
Typearray
Default["default"]

The image is placed at an X,Y coordinate relative to its parent image (such as the display). The coordinates specify the location that the anchor pixel should be located on that image. The 0,0 point on the parent is the northwest corner of the parent.

 parent
The image on which this image is rendered.
Typeattribute
Default"Display.Primary"
 x
The X position of the image anchor, relative to its parent.
Typenumber
Default0
 y
The Y position of the image anchor, relative to its parent.
Typenumber
Default0
 layer
The stacking order value of this image. 0 is on the bottom. Images with a layer value < 0 are not displayed.
Typeinteger
Default0
 alpha
The alpha blending value of this image. 0.0 is transparent; 1.0 is opaque.
Typenumber
Default1.0
 anchor
The position of the anchor expressed as a compass direction, or _C for center. For example, if the image is 150x24, anchor=_S would place the anchor at 75,24.
Typeenum 
_N, _NW, _W, _SW, _S, _SE, _E, _NE, _C
Default_NW
 width
The width of the image.
Typenumber
 height
The displayed height of the image. Note that if the number of states is greater than 0, then the height reported in this attribute will b