ObjectMaker works with two kinds of files. A class definition file contains descriptions of class templates. These templates can include method definitions that are implemented in separate C files. An instance definition file describes the static objects used by a package. This chapter describes the syntax of class definition and instance definition files.
From a programmer's point of view, ObjectMaker contains most of what is object-oriented about CodeWarrior Magic/MPW. The planning and design process usually involves building a Magic Cap package from existing classes with ObjectMaker. The actual C programming you'll do occurs when you have to write new classes or override the methods of an existing class.
Using or modifying existing classes has several benefits. It saves implementation effort and it conserves memory resources since the Magic Cap classes are stored in system ROM and special-purpose classes you develop must be stored in RAM.
In object-oriented programming systems, an object is a combination of data structures and procedures that act on that data. A class is a description of the data and behavior of a class of objects. It represents an agreement between a developer and a development system about how the object will behave when it is called upon to perform some action. Magic Cap classes are defined in a class definition file.
Magic Cap further distinguishes between two parts of a class definition: what a class can do and how it accomplishes this. A class's interface represents the first part. It describes the kind of data an instance of a class can hold and the actions it can perform. It is like a group of data structure declarations and function prototypes in a structured programming environment. An operation refers to the part of a class's interface that describes the actions it performs. A special case of an operation is an attribute which describes how to manipulate the data stored by an object. Attributes provide access to fields.
For a given class interface, a programmer can supply an implementation of a class's data storage structures and the code that performs its work or, in some cases, the programmer can indicate that these should be supplied by other classes. This implementation is divided into fields that store the data, or instance variables, of a Magic Cap object and methods that comprise the code that manipulates the data in a field or performs some action in an object. Fields and methods can take different forms to give a developer flexibility in software design.
The figure below presents this terminology in a grid.
Classes can be defined in terms of other classes through a process called inheritance. A group of related classes derived from a common source is called a class hierarchy.
A class is a static definition and by itself it doesn't do anything. At runtime, Magic Cap can create an instance of a class called an object that performs the actions advertised by the class. In Magic Cap, we often think of objects in two places. The instance definition file contains a textual representation of the static objects that ObjectMaker creates for a package. At runtime a package may create dynamic objects as well. For example, whenever the user touches new in the Notebook, a new notebook page is created dynamically.
A Magic Cap package is a collection of objects that are organized into an object hierarchy. This hierarchy is different from but related to the class hierarchy used to organize class definitions. The object hierarchy is described later in this chapter.
ObjectMaker is a simple language with a small set of Pascal-like syntax rules. Since ObjectMaker performs minimal compile-time checking you should adhere to the naming rules described in the following sections.
An ObjectMaker file is composed of a series of statements. Each statement is terminated by a semicolon. If a statement line is too long it can be spliced with a backslash \ character and continued on the following line. The backslash must be the last character on the line.
ObjectMaker recognizes two forms of comments borrowed from C and C++.
//
indicates a single line comment. Text to the
right of this delimiter is treated as a comment and ignored by
ObjectMaker.
ObjectMaker has a simple conditional compilation facility that mimics the C preprocessor. The main statements are #define, #ifdef and #endif:
#define identifier #ifdef identifier #endif
In subsequent instances the identifier string will be replaced by the token sequence.
ObjectMaker can include the contents of another file into an ObjectMaker file. This can be useful way to store definitions in one file shared by a number of ObjectMaker files. The include statement provides this feature.
include `fileName'
ObjectMaker statements can use a C-like numeric expression syntax. Standard operators like + and - as well as parentheses are supported.
The class definition file contains descriptions of classes that are unique to a given package. The name for this file is usually derived by taking the package's name and appended the .Def suffix to it. Class definition files are compiled by ObjectMaker during the package build process. Syntax for specifying fields, attributes, operations, and more is described in the following pages.
If a package doesn't define any new classes, it doesn't need a class definition file. Packages can have more than one class definition file in which case the additional files should have names derived from the first, e.g. MyClass.Def, OtherMyClass.Def, Other1MyClass.Def.
The definition of a new class includes the following:
class name | Each class has a name to associate instances of it with the class definition. |
inheritance | Classes are derived from superclasses and inherit their interfaces and implementation. |
fields | Classes store their data in fields. |
attributes | Attributes are interfaces for special operations that manipulate data in a class. |
operations | Operations describe what you can do to an object. |
methods | Methods are code that implements a class's operations and attributes. |
The interface part of the class definition specifies the operations and attributes of a class. These declare the name, arguments and return type of the class. The implementation part defines the fields and methods of a class. The fields define the types for the data holders of a class and the methods define the code or algorithms for the procedures of a class.
To implement the methods of a new class, you must provide source code for
The source code for these methods are stored in C files separately from the class definition file. The section Method Implementation describes how to structure this source code.
Classes are defined in class definition files like this:
Define Class className; // inheritance part // interface part // implementation part End Class;
The first statement in a class's definition specifies the name used to identify it to its subclasses and for objects that are instances of it.
Each class has a class number. By default, CodeWarrior Magic/MPW creates a class number for each new class. Alternatively, you can explicitly assign numbers to classes in your packages. If you do so, you must choose class numbers that are unique within a package. This may be useful if the class's interface will be public and its class numbers must be stable across different versions of the software.
Class numbers are defined with the following syntax:
class className classNumber;
Statements that defines class numbers should be placed at the beginning of the class definition file. The file ClassNumbers.Def contains a list of class numbers for Magic Cap classes.
The interior portion of a class definition contains three parts. The inheritance part determines the mechanisms by which one class is derived from other classes. The interface part describes the attributes and operations of the class. The implementation part provides the data handling for the classes fields and the algorithms for its methods.
Magic Cap is like other object-oriented systems in that it has a class hierarchy that organizes classes according to their functionality. The mechanism that enables this system of organization is called inheritance. When one class inherits from another class, it inherits its fields, methods, attributes and operations. It is called a subclass of the first class, which is also called a superclass.
CodeWarrior Magic/MPW includes a useful tool called Bowser Pro for browsing the class hierarchy and looking at different class definitions. See this book's Bowser Pro section for more information.
Classes you create can be derived from other classes through inheritance. Most classes are ultimately derived from the Object class.
ObjectMaker provides several ways in which one class can inherit from another. The syntax for enabling this process is the inherits from statement. A class definition can contain multiple inherits from statements that specify different superclasses.
The various forms of the inherits from statement can contain more than a single superclass. You should use a comma to separate them on the statement line.
The following sections describe the different forms of the inherits from statement.
inherits from superclassName;
The inherits from statement indicates the superclass from which a subclass inherits its attributes, operations, fields, and methods. Operations and attributes in the subclass that need to be changed from what is defined in a superclass can be overridden with the overrides statement described below.
Normally, a class will inherit from a superclass that is itself ultimately derived from the Object class. This kind of superclass is sometimes called a flavor class.
Mixin classes precisely define their relationship with other classes in the class inheritance scheme. Mixin classes provide the convenience of holding a group of features in a class that can be used in combination with other classes while it is not tied to a specific place in the class hierarchy. This can be more flexible than taking a general purpose class and overriding what you don't need.
Flavor classes must inherit implementation from exactly one flavor and from any number of mixins. They must inherit interface from at least one flavor and any number of mixins. Mixin classes must "mixin with" exactly one flavor class. They can inherit interface or implementation from any number of mixin classes.
inherits interface from superclassName;
This form of inheritance is useful in forcing a class to match the interface of another class and completely provide a new implementation for each attribute and operation of the inherited class. The inherits interface from statement has a performance benefit by removing the need for Magic Cap to search for the implementation of a class's methods in the interface superclass. Another benefit of this statement is to provide more type checking during class development.
inherits implementation from superclassName;
This statement allows a class to inherit the implementation of another class without guaranteeing subclasses in the hierarchy that it provides that implementation. It is a weak form of support for private methods and it is rarely used.
Abstract classes are used to collect attributes and operations into a convenient class that can then be inherited by other classes. They exist to help organize the class hierarchy and not for the immediate purpose of instantiation. Abstract classes include the keyword abstract at the top of their class definition.
Abstract classes can contain fields with the noGetter, noSetter and noMethod flags. These will be explained later in this chapter.
Mixin classes are abstract classes that are independent of Object and branch off the class hierarchy. The classes that can inherit from a particular mixin class can be limited to a specific list with the mixes in with statement.
mixes in with flavorClassName;
This statement limits the mixin class to flavorClassName and any of its subclasses. To make a mixin class applicable to any class, specify Object as the class that it can mix with. Since all classes in the class hierarchy are derived from Object this will allow the mixin class to be applied to any subclass of Object.
Mixins also provide a way to distribute functionality to disparate areas of the class hierarchy without having to gather them into a common superclass. By not gathering them, the possible overhead of fields provided by mixins is only carried by the classes that require it and not by all the subclasses of the common superclass. This can save memory on an instance by instance basis, especially in a memory limited system like Magic Cap.
Fields provide the implementation for storing data in an object. The field statement has the following syntax:
field fieldName: fieldType, [optionalFlags];
Field names should begin with a lower-case letter. The field type can be any data type or class name. The optional flags modify the properties of a field. The following list describes the different options:
getter | A getter is a method for getting the value in a field. This flag generates a getter method for the field. No interface is created for this automatic getter and a separate attribute statement should also be defined for it. |
setter | A setter is a method for setting the value in a field. This flag generates a setter method for the field. No interface is created for this automatic setter and a separate attribute statement should also be defined for it. |
noCopy | The noCopy flag limits the control an object has over the data in a field. When this flag is set, the object referenced by this field will not be copied with the object that controls it, though the object ID remains intact in the copy. In addition, when an object instance is destroyed, the object referenced by this field will not be destroyed with the object that controls it. It can be used to control access to an object during wireline encoding. This flag can only be applied to fields with objects. It is rarely used. |
noSend | The noSend flag prevents a field from being sent with an object instance that refers to it. It can be used to control access to an object during wireline encoding. This flag can only be applied to fields with objects and is rarely used. |
sendOptional | This flag controls the default wireline encoding. This flag can only be applied to fields with objects and is rarely used. |
Here is an example of a simple field:
field bookColor: Unsigned;
This specifies a field named bookColor that has the type Unsigned.
If the field definition includes a getter or setter flag, ObjectMaker generates an automatic method for these fields. The name of the automatic getter is derived from the field's name by capitalizing the first letter in its name. The automatic setter attribute also adds the prefix `Set' to the field's name.
If an attribute is new to a class, then a matching attribute statement is required. If an attribute is inherited, then getter or setter can be used to override the getter or setter flag of the inherited attribute. In that case, no additional attribute statement is needed in the subclass. This is described in the next section.
An attribute describes the interface to methods that access a class's fields. There are two forms of attributes. The first form provides a well-defined interface for the automatic methods mentioned in the previous section. Here is an example of field and attribute definitions that a class definition might include:
field visible: Boolean, getter, setter; attribute Visible: Boolean;
The first line defines a field with its type and special flags indicating that getter and setter attributes are necessary. The second line defines these attributes. It defines both the getter operation Visible and the setter operation SetVisible. Objects can use these methods to get and set the value of the visible field.
The second form of an attribute is independent of a specific field in a class. For example, attributes can be created that set and return a calculated value instead. The calculation could be based upon a field value (such as returning a percentage based on a field that maintains a fractional value), the system state (such as the current scene or the modem status), or system constants (such as the image of the General Magic logo or a system sound). In this case the package needs to provide the implementation of the getter and setter.
Attributes in class definitions are defined like this:
attribute attributeName: attributeType, [flags];
The following list describes the different attribute options:
noSetter | The noSetter flag indicates that the class provides no setter method for this attribute but that subclasses could provide one. This flag can only be used with attributes of abstract classes. |
noGetter | The noGetter flag indicates that the class provides no getter method for this attribute but that subclasses could provide one. This flag can only be used with attributes of abstract classes. |
readOnly | The readOnly flag indicates that the attribute can return a value but cannot set one, and so neither this class nor its subclasses should provide a method to do so. Subclasses can redeclare an attribute to add a setter. |
safe | The safe flag is an advisory flag to inform a high level programmer that the attribute does not need to be called in combination with any other attributes or operations. |
common | The common flag is an advisory flag indicating that the attribute will appear in Magic Script menus. All common attributes must be safe. |
scriptable | The scriptable flag indicates that the attribute should appear in Magic Script menus that list attributes and operations that can be overridden with Magic Script scripts. |
An operation describes the interface to a class's method. It is similar to a procedure declaration with a list of flags that control the operation's behavior. Operations in class definitions are defined like this:
operation operationName[(paramName: paramType)]: returnValueType, [flags];
This includes the operation's name, its return value and an optional list of parameters with their types. In addition, an operation definition may include a list of flags that control the behavior of operations.
Every method in a class has one required parameter, known as self. The self parameter represents the object ID of the object whose method is being invoked. Since every method requires this object ID as its first parameter, this parameter is omitted in the class definition file. However, you must use it in the C file that contains the source code for the class.
The following list describes options for operations:
noMethod | The noMethod flag indicates that the class does not provide a method for this operation. Concrete subclasses of a superclass must provide the method. Classes that specify the noMethod flag on their operations must be defined as abstract. |
noFail | The noFail flag indicates that the Magic Cap method dispatcher will do nothing and return 0 (if there is a return value) if the object passed to the operation is a nil object. This may provide convenience during debugging. This flag is only useful during package development on CodeWarrior Magic/MPW since all methods are treated as noFail on a communicator. |
intrinsic | The intrinsic flag indicates that this operation is called by a direct jump to the method which is faster than the usual method dispatching mechanism. Intrinsic operations can't be overridden by subclasses and can't be called by objects of other packages. There can be no other flags specified with the intrinsic flag. |
safe | The safe flag indicates that this operation does not need to be called in combination with any other attributes or operations. |
common | The common flag indicates that the operation should appear in Magic Script menus. All common operations must be safe. |
scriptable | The scriptable flag indicates that this operation should appear in Magic Script menus that list attributes and operations that can be overridden with Magic Script scripts. |
Each operation has an operation number used by Magic Cap for method dispatching. By default, ObjectMaker defines these numbers for operations. You can specify numbers for the operations in your classes in a manner similar to how class number can be specified. You might do this if your class has a public interface and you don't want the operation numbers to change across different versions of the software.
Operation numbers are defined with the following syntax:
operation operationName operationNumber;
The statement that defines an operation number should be placed at the beginning of the class definition file. Each operation number must be unique within a package.
Attributes represent a special case for operation numbers. Because two operations are created when an attribute is defined (one for the getter and one for the setter), two operation numbers must also be defined. ObjectMaker defines syntax for assigning operation numbers to attributes as follows:
attribute attributeName attributeNumber;
This assigns attributeNumber to the automatic getter and attributeNumber+ 1 to the automatic setter. So, the assignment of the attribute number below
attribute Visible 66;
is equivalent to
operation Visible 66; operation SetVisible 67;
Attribute numbers have the same requirements as operation numbers.
A class can define fields that hold data for the class itself, rather than for instances of the class. These fields are called globals. Globals in class definitions are defined like this:
global globalName: globalType;
You use FieldOf(ClassGlobals, <ClassName>Globals_<globalName>) to get a single global. Other accessors like SetFieldOf, BeginReadFieldsOf, ReadFieldsOf, etc.) can also be used to access global fields.
A class can define operations that don't require an instance of the class in order to execute. These operations are called simple intrinsics. They have the same properties as intrinsics but they do not require an object ID as their first parameter. Simple intrinsics are faster to invoke than other operations but they cannot be overridden by subclasses.
Simple intrinsics in class definitions are defined like this:
intrinsic intrinsicName(paramName: paramType): returnValueType;
As with operations, simple intrinsics can be assigned numbers that must be unique within the package. The ObjectMaker syntax for assigning an intrinsic number to a simple intrinsic in a class definition file is:
intrinsic intrinsicName intrinsicNumber;
This statement must precede the class that defines the simple intrinsic in the class definition file.
Once an operation or attribute has been defined in a superclass, a simple overrides statement can be used to provide a new implementation in a subclass. The overrides keyword can also define an implementation for a previously unimplemented operation, such as for operations that were defined with the noMethod flag in a superclass. A class can also use the overrides keyword to override an auto-getter or auto-setter method that was defined for a field of a superclass.
To override a method in a class definition, use the overrides statement:
overrides operationName;
This statement indicates that a given class will supply its own implementation for the operation.
ObjectMaker extracts code from files that have been compiled and linked and installs that code into the correct classes. ObjectMaker uses a naming convention to decide which routine's code to attach to an operation. The key part of this convention is that operations in the source file are indicated by the class name and operation name connected with an underscore. For example, a C function named TestClass_DoSomething would provide the code for the DoSomething operation of the TestClass class.
When an operation is declared or called in C source, the first parameter must be the responder, the object whose operation is being called. When an operation is defined in a class definition file (ObjectMaker source), the responder is implied but is never shown. See Magic Cap Concepts for more information.
Each Magic Cap package must have an instance definition file named Objects.Def that describes the objects used by that package. A package can have more than one instance definition files. In that case the additional files should have names that use "Objects.Def" as a suffix.
As part of the process of building a Magic Cap package, ObjectMaker compiles this instance definition file into a package along with any special classes defined in the class definition file and implemented in separate C files.
The instance definition file contains textual representations of the package's static objects. These are the objects the package creates when it is loaded into the Magic Cap environment. The package usually creates other dynamic objects at runtime but they are managed by the Magic Cap environment itself.
Instance Class [objectName] instanceID; fieldName: value; . . End Instance;
The instance definition file simply contains a list of object instances. Each object instance definition includes the name of its class, an optional object name and an instance definition id. The name can be helpful in the debugging process though it does incur some system overhead.
The instance definition ID used as a bookkeeping device for organizing instance definitions in an instance definition file. At runtime Magic Cap keeps track of a different number to refer to objects called an object ID. These numbers are not equivalent and it is a programming error to substitute one for the other.
Instance IDs should be unique within the package. The Get Unique Instance ID menu item in the Utils menu in CodeWarrior Magic/MPW can choose a suitable number for this field. If you do select instance ids manually, be sure to choose numbers that are small and not too far apart to avoid putting a memory burden on the Magic Cap runtime environment.
The objects in a definition file do not have to be in numerical order (or any other special order). Every object in the file must have a unique instance definition ID, and instance definition IDs must be positive integers.
The interior of an instance definition contains a list of field initialization statements with the name of the field followed by its value. These correspond directly to the fields in the object's class or superclass and must use the same order found in the class definitions. The different values that a field can have are described in the next section.
The instance definition is finished with an End Instance statement.
Magic Cap Simulator can translate objects from the Magic Cap runtime environment to instance definition files. This process of decompiling is called dumping in CodeWarrior Magic/MPW. Dumping is a vital feature for moving between textual and live binary representations of objects. You can also convert objects directly from Magic Cap to text one at a time.
One way to develop an instance definition file is to write a series of instance definitions, build a Magic Cap package with CodeWarrior Magic/MPW, modify the objects with construction mode and then dump them back into CodeWarrior Magic/MPW. While this is a recommended method for developing instance definitions it does remove any comments you may have stored in your instance file. So comments should be placed carefully in the instance definition file so that you can easily fold in your modified instance definitions.
If you add an object to a package by using the Magic Cap software and then dumping it to the Objects.Def file, CodeWarrior Magic/MPW assigns a number in hexadecimal format. Delete the hex value and replace it with a number returned by the Get Unique Instance ID item from the Utils menu.
The objects in the instance definition file are structured in a tree-like hierarchy. The top of this hierarchy is the SoftwarePackage object. Every other object in the instance definition file must be referred to by at least one other object and ultimately referred to by SoftwarePackage.
The following illustration represents the object hierarchy used in the HelloWorld package. While this is a very simple package, more complex packages will have the same basic structure. More complex packages will tend to have a deeper tree branching from the subviews of the scene or will have multiple scenes pointed to by the standard places list.
Each object in this package has an instance definition ID number. The choice of numbers for instance definition ID's is up to the package developer. You should choose instance definition ID's that are small and closely packed because this avoids putting a memory burden on the Magic Cap runtime environment.
Each object can contain any number of fields. The instance definition file lists the values that these fields have when the package is loaded.
fieldName: value;
Each field initialization statement has a pair of tokens separated by a colon and terminated with a semicolon. The token on the left is the name of the field beginning with a lower-case letter. The token on the right is the value of the field. Each value has a type that indicates the kind of data that the field can contain. For example, one field may contain a floating point value and another may contain an indexical.
The following sections describe the different types a field value can have.
An object reference takes the following form:
(Class nameString instanceID)
Class is the name of the class that the object is instantiated from. nameString is the name of the object instance. instanceID should be unique within the instance definition file.
The object reference information in the field initialization statement should match the information used to define the instance. For example,
target: (Greeter 'MyHelloWorld' 9);
Indexicals allow you to refer to standard system objects, important objects in your package or dynamic objects like the current scene. Standard system objects and dynamic objects are listed in Indexicals.h. Indexicals can be a reference to an object or a list of objects.
The most common use of indexicals is to get to an item that is an element of a list. For example, Indexicals.h contains a list of standard text styles. To use one of the text styles in your object, such as Book 12, without having a copy of that object in your package, you can look up Book in Indexicals.h and you will see:
#define iBook12 MakeIndexical(60,1)
The numbers in parentheses (60,1) refer to the first element in the sixtieth object list of standard system objects. (Note that the object list of standard system objects is called the system root list.) To use this in your package, you would have a line like the following:
labelStyle: iBook12; // recommended labelStyle: {60,1}; // not recommended
The first form of representing indexicals is strongly preferred over the second form. It is better programming style to leave the management of indexical numbers to ObjectMaker and use the predefined numbers in Indexicals.h. Unfortunately, Magic Cap Simulator dumps objects as raw indexical numbers. CodeWarrior Magic/MPW has a script named Convert Dumped Indexicals that handles this conversion process.
Flat indexicals refer to an object in the system root list, rather than an object in a list stored in the system root list. For example:
#define iTextStyles MakeFlatIndexical(60) #define iDatebook MakeFlatIndexical(2)
To refer to a flat indexical in the instance definition file, you would use a field definition statement like the following:
field: iDatebook; // recommended field: {2}; // not recommended
Package indexicals serve the same purpose as system indexicals but they are restricted to a package. In this case, the syntax is slightly different, you need to let the system know that you are referring to a package indexical, so you use {{n}} instead of {n}. You might have a list of special text styles in your package, which you have put into the 25th entry of the SoftwarePackage object, to refer to the second text style in that list. The definition of a package indexical for this would be the following:
labelStyle: ipkgTextStyle; // recommended labelStyle: {{25,2}}; // not recommended
Some Magic Cap classes, like Control and AttributeText, define fields that require operation numbers as values. System operation numbers are defined for the operations in system classes. The system operation numbers are listed in OperationNumbers.h.
Package operation numbers are assigned to all package-defined operations when a class definition file is compiled by ObjectMaker. These package operation numbers are stored in the package's PackageOperationNumbers.h file. CodeWarrior Magic/MPW has a separate instance of this file for each communicator platform.
For every system or package operation number, a constant of the form operation_OperationName is defined.
To specify an operation number as the value for a field in Objects.Def, use either a system operation number, a package operation number, or the constant for either:
operation: operation_ShowOrHide; // recommended operation: 0x000003EC; // not recommended
Note that it's a good idea to explicitly define your package operation numbers in the class definition file. That way, ObjectMaker always translates the constant to the correct operation number, regardless of additional operations added to your class definitions. See AccessDemo for an example.
Lightweight objects are used for Magic Script scripts. You will see them in an Objects.Def file that contains compiled Magic Script scripts. The following declares a lightweight integer. See the Calculator package for an example. See Generic.h for other lightweight data types. Note: You'll see these in Objects.Def files but you won't necessarily create any yourself.
object: LtWtOpNum(operation_operationName); object: LtWtInteger(number);
The object runtime defines a special lightweight object ID that represents the absence of an object. This ID is defined by the symbol nilObject.
A field can extract its value from a file with the include keyword. For example, it may be more convenient to store the data for an image in a separate file and refer to it indirectly. The include keyword has three syntax variants.
data: include `fileName'; data: include `fileName' start_offset; data: include `fileName' start_offset:end_offset;
The first form includes an entire file as the value for a field. The second form use the begin value as an offset into the file. The third form uses both begin and end to limit the portion of the file to extract. These last two forms are not inclusive. For example,
data: include `table' 0:32;
includes bytes 0 through 31 of the file table.
The following declare a field that is 32 bits in length.
myLong: 6; viewFlags: 0x11005200;
The first example has an integer number and the second example has a hex value that is 32 bits in length.
The following declares a field that is 16 bits in length.
myShort: 6.s;
The following declares a field that is 8 bits in length.
myByte: 6.b;
The following declares a field that is 1 bit in length.
autoActivate: true; // or false
Strings can include ASCII text, special characters or Unicode constants.
name: 'Hello World';
Strings can include the following escape characters:
\n new-line \t tab \' single-quote \\ back slash \xdddd Unicode constant
A Fixed value is 32 bits in length with 16 bits of integer and 16 bits of fractional data.
width: 1.0; // hex equivalent: 00010000
ObjectMaker uses the $ character to indicate a string of characters to be interpreted as hexadecimal.
object: $00A6E27C;
Many objects store unformatted data as hex strings in their extra data (the variable length portion of an object that can exist in addition to its fields). Objects like images and cards often have extra data.
data: $0400 007F FE40 F700 031F FFFF E4F9 000A \ 1701 FD40 017A 0000 01AA A4FD 000E 0FD0;
Positional data can be specified with either pixels or microns. A pixel is the basic image unit of a graphics display. A micron is a smaller image unit used for more precise imaging calculations. The following relationship converts between these two systems: 1 pixel = 256 microns.
Both pixels and microns are stored as 32-bit data types. They are both represented by using angle brackets. If the value between the <> is a fixed value that includes a decimal point it is a pixel; otherwise it is a micron. For example,
height <28.0>; // 28 pixels recommended height <7168>; // 7168 microns not recommended
See the book Magic Cap Concepts for more information on the Magic Cap imaging model.
An object can store a location on the communicator's display with a Dot value. The value is represented as a horizontal and vertical coordinates in a coordinate system with the origin in the center of the display.
location: <20.0,30.0>; // x-y
The location of a Dot can be specified in either fixed values or integers. If the values used are fixed, the location is interpreted in pixel units; otherwise microns are used.
A Box is a rectangular region of the Magic Cap communicator's display. The value is represented as a set of four 32-bit values. At with Dot, if the values are specified the Fixed type, its units are interpreted as pixels; otherwise they are interpreted as microns.
region: <5.0, 40.0, 80.0, 90.0>; // left, top, right, bottom