Portabl E's standard functionality

  by Chris Handley
  Last updated 07.11.2022.

All the functionality listed here is intended to be completely portable (i.e. OS independant). However, some of the MODULEs may not be implemented yet for all supported OSes (typically Linux & Windows), so they list which OSes are supported.

If you are not sure which modules to use, then please be sure to read chapter 8. What do the different MODULEs do?.

NOTE 1: While methods are shown in the form METHOD method(), this is not valid syntax for Portabl E code (although that might change!).

NOTE 2: If you see OWNS as part of a variable's type, you can safely ignore it, because that is what Portabl E currently does! However, it is a hint that ownership (i.e. deallocation responsibility) is being handed over. Thus an OWNS parameter shows that the procedure takes ownership, while an OWNS return value shows that the procedure passes ownership to the caller.


CONTENTS


1. Supported immediate values

This is a list of all the kinds of values that can be used:

These are documented in the original AmigaE manual:

cshandley.co.uk/amigae


Go back to CONTENTS


2. Supported expressions

This is a list of all expressions that can be used:

  storage := expr
  ++ storage
  -- storage
  storage ++
  storage --
  array[expr]
  - expr
  ( expr )
  expr !! type
  expr AND expr
  expr OR  expr
  expr XOR expr
  expr SHL expr
  expr SHR expr
  expr BUT expr
  expr  = expr
  expr >= expr
  expr >  expr
  expr <= expr
  expr <> expr
  expr <  expr
  expr + expr
  expr - expr
  expr * expr
  expr / expr
  procedure(...)
  SUPER procedure(...)
  CALLBACK procedure()
  NEW storage
  NEW object.method(...)
  object::objectType
  object.member
  object.method(...)
  SUPER self.method(...)
  IF expr THEN expr ELSE expr
  NOT expr
  SIZEOF type
  TYPEOF objectType
  ADDRESSOF variable
  NATIVE {native group} ... ENDNATIVE
  EMPTY

Most of these expressions are documented in the original AmigaE manual:

cshandley.co.uk/amigae

But when reading that manual, please beware that:

Note that:

Go back to CONTENTS


3. Supported statements

This is a list of all statements that can be used (inside of a procedure). The full version of each statement is given, with optional parts enclosed in [square brackets]. Note that [...] is used to indicate that the previous optional part may be repeated further.

  expr
  
  
  statement ; statement
  
  
  IF expr THEN statement [ELSE statement]
  
  
  IF expr
  	statements
  [ELSE IF expr
  	statements]
  [ELSE IF expr
  	statements]
  [...]
  [ELSE
  	statements]
  ENDIF
  
  
  END storage [,storage] [,storage] [...]
  
  
  RETURN [ expr [,expr] [,expr] [...] ]
  
  
  FOR storage := expr TO expr [STEP expr] DO statement
  
  
  FOR storage := expr TO expr [STEP expr]
  	statements
  ENDFOR [IF expr]
  
  
  LOOP
  	statements
  ENDLOOP
  
  
  REPEAT
  	statements
  UNTIL expr
  
  
  WHILE expr DO statement
  
  
  WHILE expr
  	statements
  ENDWHILE [IF expr]
  
  
  SELECT expr
  [CASE expr ; statements]
  [CASE expr ; statements]
  [...]
  [DEFAULT ; statement]
  ENDSELECT
  
  
  SELECT constant OF expr
  [CASE constant [TO constant] [, constant] [...] ; statements]
  [CASE constant [TO constant] [, constant] [...] ; statements]
  [...]
  [DEFAULT ; statements]
  ENDSELECT

Most of these statements are documented in the original AmigaE manual:

cshandley.co.uk/amigae


Go back to CONTENTS


4. Supported declarations & definitions

This is a list of all the declarations & definitions which can be used (outside of a procedure). Note that [...] is used to indicate that the previous optional part may be repeated further, while [xxx ...] indicates that something comes after xxx but for brevity it is not shown. The | character is used to separate several possible options.


OPT option[=value] [, option[=value]] [...]

MODULE 'name' [, 'name'] [...]


RAISE quadcharacter IF procedure() comparison expression [, ...]

RAISE quadcharacter IF class.method() comparison expression [, ...]


CONST constant = expr [, constant = expr] [...]

ENUM constant [= expr] [, constant [= expr]] [...]

SET constant [, constant] [...]


TYPE type IS type

OBJECT object [OF object]

	[PRIVATE|PROTECTED|PUBLIC|member[:type]] [, ...]
	[...]
ENDOBJECT

CLASS object [[UNGENERIC] [ORPHAN] OF object [IMPLEMENTS object]]

	[PRIVATE|PROTECTED|PUBLIC|member[:type]] [, ...]
	[...]
ENDCLASS


STATIC variable IS [list|'immediate string']

DEF variable[:type] [, variable[:type]] [...]


PROC procedure(...) [[NEW] OF class [ORPHAN]] [RETURNS ...] [PROTOTYPE|REPLACEMENT] [IS ...]

	[DEF ...]
	statements
[FINALLY
	statements]
ENDPROC [expr [, expr] [...]]

FUNC function(...) [OF function] [IS ...]

	[DEF ...]
	statements
[FINALLY
	statements]
ENDPROC [expr [, expr] [...]]


Most of these statements are documented in the original AmigaE manual:

cshandley.co.uk/amigae

But when reading that manual, please beware that:

Note that:

Go back to CONTENTS


5. Built-in procedures

This is a list of all procedures that are built-in to Portabl E.

5.1. I/O

  PROC Print( fmtString:ARRAY OF CHAR, arg=0, ...)
  PROC PrintL(fmtString:ARRAY OF CHAR, args=NILL:ILIST)
  PROC PrintFlush()

Print() outputs the formatted string fmtString to stdout, with any additional arguments being used by the relevant soft escape codes (such as '\d'). Output may be buffered, and so may not appear immediately, especially if it does not end in a new line. Note that the "..." means it supports an unlimited number of parameters.

PrintL() is the same as Print(), except that it takes it's optional arguments as an ILIST. Can currently handle up to 20 optional items.

PrintFlush() flushes the output buffer, so everything that was Print()ed is shown.

  PROC ReopenStdOut(fileName:ARRAY OF CHAR)
  PROC ReopenStdIn( fileName:ARRAY OF CHAR)
  PROC SetStdOut(fileHandle:PTR) RETURNS oldstdout:PTR   ->depreciated
  PROC SetStdIn( fileHandle:PTR) RETURNS oldstdin :PTR   ->depreciated
  PROC Out(fileHandle:PTR, char:CHAR) RETURNS value
  PROC Inp(fileHandle:PTR) RETURNS char:INT
  PROC OpenInOut(fileName:ARRAY OF CHAR) RETURNS fileHandle:PTR
  PROC CloseInOut(fileHandle:PTR)

ReopenStdOut() & ReopenStdIn() change the stdout & stdin streams (used by Print()/etc) to the given fileName. Note that on most targets the values of stdout & stdin won't change, but this is not guaranteed.

SetStdOut() & SetStdIn() change the stdout & stdin streams (used by Print()/etc) to the given fileHandle. Depreciated in favour of ReopenStdOut() & ReopenStdIn(). Note that SetStdIn() & SetStdOut() don't work on AROS anymore.

Out() writes the supplied character char to the file handle, returning the number of characters actually written - so anything other than 1 is an error. You would typically use the stdout file handle.

Inp() reads & returns one character from the supplied file handle. An error is indicated by returning -1. You would typically use the stdin file handle.

OpenInOut() returns a fileHandle for the given file, which can be used with SetStdOut()/etc.

CloseInOut() closes the fileHandle, so that it can't be used anymore.

5.2. String

  PROC StrCmp(      first:ARRAY OF CHAR, second:ARRAY OF CHAR, len=ALL, firstOffset=0, secondOffset=0) RETURNS match:BOOL
  PROC StrCmpNoCase(first:ARRAY OF CHAR, second:ARRAY OF CHAR, len=ALL, firstOffset=0, secondOffset=0) RETURNS match:BOOL
  PROC StrLen(string:ARRAY OF CHAR) RETURNS length
  PROC Val(string:ARRAY OF CHAR, addrRead=NILA:ARRAY OF LONG, startPos=0) RETURNS value, read   ->addrRead is depreciated
  PROC InStr(      haystack:ARRAY OF CHAR, needle:ARRAY OF CHAR, startPos=0) RETURNS matchPos
  PROC InStrNoCase(haystack:ARRAY OF CHAR, needle:ARRAY OF CHAR, startPos=0) RETURNS matchPos
  PROC TrimStr( string:ARRAY OF CHAR) RETURNS string:ARRAY OF CHAR
  PROC UpperStr(string:ARRAY OF CHAR) RETURNS string:ARRAY OF CHAR
  PROC LowerStr(string:ARRAY OF CHAR) RETURNS string:ARRAY OF CHAR
  PROC AstrCopy(destination:ARRAY, source:ARRAY OF CHAR, destSize)
  PROC OstrCmp(      string1:ARRAY OF CHAR, string2:ARRAY OF CHAR, max=ALL, string1Offset=0, string2Offset=0) RETURNS sign:RANGE -1 TO 1
  PROC OstrCmpNoCase(string1:ARRAY OF CHAR, string2:ARRAY OF CHAR, max=ALL, string1Offset=0, string2Offset=0) RETURNS sign:RANGE -1 TO 1
  PROC QuadToStr(value:QUAD) RETURNS string:ARRAY OF CHAR

StrCmp() compares the first string against the second, and returns TRUE if they matched. len gives how many characters to compare (from the beginning), with the special ALL constant meaning compare everything. firstOffset & secondOffset allow you to specify an offset into the first & second strings respectively (to avoid pointer arithmetic).

StrCmpNoCase() is a case-insensitive version of StrCmp(). This procedure was not present in AmigaE.

StrLen() returns the length of the supplied zero-terminated string. It can be slow for very large strings.

Val() parses the supplied string, optionally starting from a startPos position other than 0, and returns the value of the integer number. Leading spaces & tabs are skipped. Hexadecimal & binary numbers are accepted if they are preceeded by $ or % respectively. A - minus sign will make the number negative. read is used to return the number of characters read, but will be 0 to indicate an error if no number could be parsed. addrRead is depreciated, but if it is supplied then the number of characters read is also written to the first item of that array.

InStr() searches the haystack string for an occurance of needle, optionally starting from a startPos position other than 0. It returns the position/offset at which needle was found, or -1 if there was no match.

InStrNoCase() is a case-insensitive version of InStr(). This procedure was not present in AmigaE.

TrimStr() returns a string pointing to the first non-empty character (not a tab, space, linefeed, etc) in the supplied string.

UpperStr() modifies the supplied string to be all uppercase. It returns the supplied string for convenience.

LowerStr() modifies the supplied string to be all lowercase. It returns the supplied string for convenience.

AstrCopy() stands for "Array STRing COPY", and copies the contents of the source string into the destination string, ensuring that the destination is always zero-terminated. destSize gives the maximum number of characters that destination can hold.

OstrCmp() performs an ordered string comparison between string1 & string2. Conceptually you can think of it as returning the Sign() of "string2 - string1". Thus it returns 0 if they are identical, 1 if string2 > string1, and -1 if string2 < string1. max gives how many characters to compare (from the beginning), with the special ALL constant meaning compare everything. string1Offset & string2Offset allow you to specify an offset into string1 & string2 respectively (to avoid pointer arithmetic).

OstrCmpNoCase() is a case-insensitive version of OstrCmp(). This procedure was not present in AmigaE.

QuadToStr() converts a QUAD value into a string, for easy Print()ing. Very useful for printing exception. Beware that it returns the same string each time (but modified to match the QUAD value), so you should copy it if you need to call QuadToStr() again before using the first returned string.

5.3. Logical

  PROC  And(a, b) RETURNS value   ->depreciated, instead use AND
  PROC   Or(a, b) RETURNS value   ->depreciated, instead use OR
  PROC  Xor(a, b) RETURNS value   ->depreciated, instead use XOR
  PROC  Shl(a, b) RETURNS value
  PROC  Shr(a, b) RETURNS value
  PROC  Not(a)    RETURNS value   ->depreciated, instead use NOT

And() returns a bit-wise And of the supplied values. Depreciated in favour of AND.

Or() returns a bit-wise Or of the supplied values. Depreciated in favour of OR.

Xor() returns a bit-wise Exclusive-Or of the supplied values. Depreciated in favour of XOR.

Shl() returns a arithmetically shifted left by b bits. Unlike SHL it accepts negative values for b.

Shr() returns a arithmetically shifted right by b bits. Unlike SHR it accepts negative values for b.

Not(a) returns a bit-wise inversion of the supplied value. Depreciated in favour of NOT.

5.4. Maths

  PROC  Mul(a, b) RETURNS value   ->depreciated, instead use *
  PROC  Div(a, b) RETURNS value   ->depreciated, instead use /
  PROC  Min(a, b) RETURNS value
  PROC  Max(a, b) RETURNS value
  PROC  Odd(a)    RETURNS boolean:BOOL
  PROC Even(a)    RETURNS boolean:BOOL
  PROC  Rnd(max)  RETURNS num
  PROC RndQ(seed) RETURNS num
  PROC  Abs(a) RETURNS value
  PROC Sign(a) RETURNS value:RANGE -1 TO 1
  PROC Bounds(num, min, max) RETURNS value
  PROC FastMod(a, b) RETURNS c
  PROC Mod(a, b) RETURNS c, d
  PROC Pow(a, b) RETURNS value

Mul() returns a multiplied by b. Depreciated in favour of *.

Div() returns a divided by b. Depreciated in favour of /.

Min() returns the smaller of the two supplied values.

Max() returns the larger of the two supplied values.

Odd() returns TRUE if the supplied value is odd (not wholly divisible by 2).

Even() returns TRUE if the supplied value is even (wholly divisible by 2).

Rnd() returns a pseudo-random number in the range 0 to max-1. To initialise the internal seed, call Rnd() with a negative number. The returned value may be limited to the range of LONG.

RndQ() returns a pseudo-random number quicker than Rnd() does, but the value covers the range of a whole VALUE (although it may be limited to the range of LONG for some targets). The returned value should be used as the value of seed in the next call.

Abs() returns the absolute (positive) version of the supplied value.

Sign() returns -1 if the supplied value is negative, +1 if it is positive, and 0 if it is 0.

Bounds() returns the number num bounded by the range min to max. It is equivalent to:

  IF num < min THEN min ELSE IF num > max THEN max ELSE num

FastMod() divides a by b, returning ONLY the remainder c. It is roughly twice as fast as Mod().

Mod() divides a by b, returning the remainder c & the division result d. Mathematically c is equivalent to "a modulo b", while d is "a / b".

Pow() returns a raised to the power b. This procedure was not present in AmigaE.

PROC BigMax(a:BIGVALUE, b:BIGVALUE) RETURNS c:BIGVALUE PROC BigMin(a:BIGVALUE, b:BIGVALUE) RETURNS c:BIGVALUE PROC BigFastMod(a:BIGVALUE, b) RETURNS c

BigMax(), BigMin() & BigFastMod() perform BIGVALUE equivalents of Max(), Min() & FastMod().

5.5. Floating point

  PROC Fsin(a:FLOAT) RETURNS float:FLOAT
  PROC Fcos(a:FLOAT) RETURNS float:FLOAT
  PROC Ftan(a:FLOAT) RETURNS float:FLOAT
  PROC Fasin(a:FLOAT) RETURNS float:FLOAT
  PROC Facos(a:FLOAT) RETURNS float:FLOAT
  PROC Fatan(a:FLOAT) RETURNS float:FLOAT
  PROC Fsinh(a:FLOAT) RETURNS float:FLOAT
  PROC Fcosh(a:FLOAT) RETURNS float:FLOAT
  PROC Ftanh(a:FLOAT) RETURNS float:FLOAT
  PROC Fabs( a:FLOAT)  RETURNS float:FLOAT
  PROC Ffloor(a:FLOAT) RETURNS float:FLOAT
  PROC Fceil( a:FLOAT) RETURNS float:FLOAT
  PROC Fexp(  a:FLOAT) RETURNS float:FLOAT
  PROC Flog(  a:FLOAT) RETURNS float:FLOAT
  PROC Flog10(a:FLOAT) RETURNS float:FLOAT
  PROC Fsqrt( a:FLOAT) RETURNS float:FLOAT
  PROC Fpow(  a:FLOAT, b:FLOAT) RETURNS float:FLOAT
  PROC RealVal(string:ARRAY OF CHAR) RETURNS value:FLOAT, read

Fsin(), Fcos() & Ftan() perform floating-point Sine, Cosine & Tangent in radians.

Fasin(), Facos() & Fatan() perform floating-point Arc Sine, Arc Cosine & Arc Tangent in radians.

Fsinh(), Fcosh() & Ftanh() perform floating-point Hyperbolic Sine, Hyperbolic Cosine & Hyperbolic Tangent in radians.

Fabs() performs a floating-point version of Abs()

Ffloor() & Fceil() calculate the lowest & highest whole-number float of the supplied value.

Fexp() calculates e raised to the supplied power.

Flog() calculates the natural log of the supplied value.

Flog10() calculates the log base 10 of the supplied value.

Fsqrt() calculates the square root of the supplied value.

Fpow() performs a floating-point version of Pow(). Please be warned that the order of the parameters is the opposite of that in AmigaE.

RealVal() performs a floating-point version of Val().

5.6. Exceptions

  PROC Raise(e:QUAD)   ->depreciated, instead use Throw()
  PROC Throw(e:QUAD, i=NILA:ARRAY OF CHAR)
  PROC ReThrow()
  PROC PrintException()

Raise() throws exception e, with exceptionInfo set to NILA. This is depreciated in favour of Throw().

Throw() throws exception e, with exceptionInfo set to i.

ReThrow() throws the last exception again, if the global exception is not 0, otherwise it does nothing. Hardly needed since Portabl E automatically does this at the end of every FINALLY section.

PrintException() is an easy way of reporting an exception. If there was no exception then it will do nothing. If you want to customise the output, then you can easily write your own version using Print() & QuadToStr()!

5.7. Memory

  PROC New( size, noClear=FALSE:BOOL) RETURNS mem:ARRAY
  PROC NewR(size, noClear=FALSE:BOOL) RETURNS mem:ARRAY
  PROC Dispose(mem:ARRAY) RETURNS NILA

New() allocates & returns a memory block of size bytes. Normally the memory is cleared (zeroed), but if noClear is TRUE then it isn't. If allocation fails then it returns NILA. Note that memory is automatically deallocated at the end of the program.

NewR() is the same as New(), except that if allocation fails it raises the MEM exception.

Dispose() deallocates the provided memory block, which must have been allocated with New() or NewR(). It allows mem to be NILA. It returns NILA for convenience.

  PROC FastNew(size, noClear=FALSE:BOOL) RETURNS mem:ARRAY
  PROC FastDispose(mem:ARRAY, size) RETURNS NILA
  PROC MemCopy(target:ARRAY, source:ARRAY, sizeInBytes, targetOffsetInBytes=0, sourceOffsetInBytes=0) RETURNS target:ARRAY

FastNew() is like NewR(), except that it is super-fast & does not significantly fragment memory. It does this using an enhanced TLSF algorithm, which allocates memory in larger blocks. On more modern OSes this is unnecessary, and so it simply calls NewR() in thoses cases.

FastDispose() is the Dispose() equivalent for FastNew(), but it needs to know the size of the block being deallocated. Unlike AmigaE, memory is returned to the OS, although only if everything in the "larger block" has been deallocated (otherwise the memory is recycled for the next FastNew() call).

MemCopy() copies sizeInBytes bytes from the source memory block into the target. targetOffsetInBytes & sourceOffsetInBytes allow you to specify an offset into the target & source memory respectively (to avoid pointer arithmetic). It returns the target array for convenience. This procedure was not present in AmigaE, but it provides a portable alternative to the Amiga's CopyMem().

5.8. Arrays

  PROC NewArray(sizeInItems, itemSizeInBytes:INT) RETURNS mem:PTR
  PROC DisposeArray(array:ARRAY) RETURNS NILA
  PROC ArrayCopy(target:PTR, source:ARRAY, sizeInItems, itemSizeInBytes:INT) RETURNS target:ARRAY

NewArray() allocates & returns an array of sizeInItems items, which are itemSizeInBytes bytes per item. Although it should return an ARRAY, it currently returns a PTR to force you to use OPT POINTER (since it may not be implementable for Java-like languages).

DisposeArray() deallocates the provided array, which must have been allocated with NewArray(). It returns NILA for convenience.

ArrayCopy() copies sizeInItems items, which are itemSizeInBytes bytes per item, from the source array into the target array. It returns the target array for convenience. Although target should be an ARRAY, it is currently a PTR to force you to use OPT POINTER (since it may not be implementable for Java-like languages). Therefore you must cast target to a plain ARRAY type, using !!ARRAY , for it to compile.

5.9. E-lists

  PROC NewList(maxLen) RETURNS list:LIST
  PROC DisposeList(list:LIST) RETURNS NILL
  PROC ListCopy(list: LIST, other:ILIST, len=ALL) RETURNS list:LIST
  PROC ListAdd( list: LIST, other:ILIST, len=ALL) RETURNS list:LIST
  PROC ListMax( list: LIST) RETURNS max:VALUE
  PROC SetList( list: LIST, newLen)
  PROC ListLen( list:ILIST) RETURNS len:VALUE
  PROC ListCmp( list:ILIST, other:ILIST, len=ALL) RETURNS match:BOOL
  PROC ListItem(list:ILIST, index) RETURNS value

NewList() allocates & returns an e-list of maxLen items.

DisposeList() deallocates the provided e-list. It returns NILL for convenience.

ListCopy() replaces the contents of the list with that from the other list. len gives how many items to copy (from the beginning), with the special ALL constant meaning copy everything. It returns the list for convenience.

ListAdd() is similar to ListCopy(), except that the items are appended to the list.

ListMax() returns the maximum allowed length of the list.

SetList() changes the current length of the list to newLen items.

ListLen() returns the current length of the list.

ListCmp() compares the list against the other list, and returns TRUE if they match. len gives how many items to compare (from the beginning), with the special ALL constant meaning compare everything.

ListItem() returns item index from the list.

5.10. E-strings

  PROC NewString(maxLen) RETURNS eString:STRING
  PROC DisposeString(eString:STRING) RETURNS NILS
  PROC StrCopy( eString:STRING, string:ARRAY OF CHAR, len=ALL, pos=0) RETURNS eString:STRING
  PROC StrAdd(  eString:STRING, string:ARRAY OF CHAR, len=ALL, pos=0) RETURNS eString:STRING
  PROC StrJoin(s1=NILA:ARRAY OF CHAR, ..., s19=NILA:ARRAY OF CHAR) RETURNS newString:STRING
  PROC EstrLen( eString:STRING) RETURNS len:VALUE
  PROC StrMax(  eString:STRING) RETURNS max:VALUE
  PROC RightStr(eString:STRING, eString2:STRING, n) RETURNS eString:STRING
  PROC MidStr(  eString:STRING, string:ARRAY OF CHAR, pos, len=ALL) RETURNS eString:STRING
  PROC SetStr(  eString:STRING, newLen)
  PROC StringF( eString:STRING, fmtString:ARRAY OF CHAR, arg1=0, ..., arg8=0) RETURNS eString:STRING, len
  PROC StringFL(eString:STRING, fmtString:ARRAY OF CHAR, args=NILL:ILIST)     RETURNS eString:STRING, len
  PROC RealF(   eString:STRING, value:FLOAT, decimalPlaces=8) RETURNS eString:STRING
  PROC ReadStr(fileHandle:PTR, eString:STRING) RETURNS fail:BOOL
  PROC Link(    complex:STRING, tail:OWNS STRING) RETURNS complex:STRING
  PROC Next(    complex:STRING) RETURNS tail:STRING
  PROC Forward( complex:STRING, num) RETURNS tail:STRING

NewString() allocates & returns an e-string of maxLen items.

DisposeString() deallocates the provided e-string. It returns NILS for convenience.

StrCopy() replaces the contents of the eString with that from the string. len gives how many characters to copy (from the beginning), with the special ALL constant meaning copy everything. pos gives the position of the first character to copy. It returns the eString for convenience.

StrAdd() is similar to StrCopy(), except that the items are appended to the eString.

StrJoin() returns a new e-string which contains all of the supplied strings appended together. If any supplied string is NILA, then it will simply be ignored. This procedure was not present in AmigaE.

EstrLen() returns the current length of the eString. This is much faster than StrLen().

StrMax() returns the maximum allowed length of the eString.

RightStr() fills the eString with the last n characters of eString2. It returns the eString for convenience.

MidStr() replaces the contents of the eString with the given range from the string. pos gives the start position in string (with 0 being the beginning), while len gives how many characters to copy (from the start position), with the special ALL constant meaning copy everything. It returns the eString for convenience.

SetStr() changes the current length of the eString to newLen characters.

StringF() is similar to Print(), except that output now goes to the eString instead of stdout.

StringFL() is the same as StringF(), except that it takes it's optional arguments as an ILIST. Can currently handle up to 20 optional items.

RealF() writes the float value into the eString as an ASCII representation, with decimalPlaces digits after the decimal point. It returns the eString for convenience.

NOTE: The name of this procedure isn't strictly correct, so it may eventually be changed.

ReadStr() reads a string (ending in ASCII 10) from the fileHandle into the eString. It returns TRUE if an error occured, or an EOF was reached. The only file handle you are likely to use is stdin.

Link() puts the tail e-string into the next field of the complex e-string. It returns the complex e-string for convenience. Note that the complex e-string now owns the tail e-string, and will deallocate it when it is deallocated.

Next() returns the next field of the complex e-string. Next(NILS) safely returns NILS.

Forward() is similar to Next(), except that it goes forward num links instead of 1. You may safely call Forward() with a num that is too large.

5.11. Endian & CHAR value

  PROC CharToUnsigned(char:CHAR) RETURNS value
  PROC UnsignedToChar(value) RETURNS char:CHAR

CharToUnsigned() & UnsignedToChar() allow you to convert a CHAR to an unsigned value (typically between 0 & 255) & back again. You need this when comparing a CHAR with an integer value, because CHAR has unknown signedness in Portabl E.

  PROC BigEndianINT( in:INT ) RETURNS out:INT
  PROC BigEndianLONG(in:LONG) RETURNS out:LONG
  PROC BigEndianBIGVALUE(in:BIGVALUE) RETURNS out:BIGVALUE

BigEndianINT(), BigEndianLONG() & BigEndianBIGVALUE() return a value with swapped endianness, when used on a Little Endian processor (like x86), while they do nothing to the value when used on a Big Endian processor (like 68k or PPC). They should be used when reading or writing a value that is stored in Big Endian format.

You are encouraged to use Big Endian format for storing values, partly because they are easily read using a hex editor (since the largest digits are on the left), and partly because this format takes less effort on Big Endian processors (which tend to be less powerful).

Note that these BigEndian...() functions are the equivalent of the depreciated EndianSwap...() functions (which are currently still provided).

  PROC LittleEndianINT( in:INT ) RETURNS out:INT
  PROC LittleEndianLONG(in:LONG) RETURNS out:LONG
  PROC LittleEndianBIGVALUE(in:BIGVALUE) RETURNS out:BIGVALUE

LittleEndianINT(), LittleEndianLONG() & LittleEndianBIGVALUE() return a value with swapped endianness, when used on a Big Endian processor (like 68k or PPC), while they do nothing to the value when used on a Little Endian processor (like x86). They should be used when reading or writing a value that is stored in Little Endian format.

  PROC SwapEndianINT( in:INT ) RETURNS out:INT
  PROC SwapEndianLONG(in:LONG) RETURNS out:LONG
  PROC SwapEndianBIGVALUE(in:BIGVALUE) RETURNS out:BIGVALUE

SwapEndianINT(), SwapEndianLONG() & SwapEndianBIGVALUE() always return a value with swapped endianness, whatever processor is used. These functions should not normally be needed, but are provided for completeness.

  PROC IsBigEndian()    RETURNS    isBigEndian:BOOL
  PROC IsLittleEndian() RETURNS isLittleEndian:BOOL

IsBigEndian() & IsLittleEndian() return TRUE or FALSE to indicate whether it is being used on a Little Endian or Big Endian processor. (Might be useful to avoid processing all items of an array with BigEndian...() or LittleEndian...(), when they will do nothing for the current processor type. Or possibly to use SwapEndian...() only when needed.)

5.12. Class type

  PROC HaveSameClassTypes(first:CLASSTYPE, second:CLASSTYPE) RETURNS same:BOOL

HaveSameClassTypes() compares the first class type against the second, and returns TRUE if they were the same. For more information please see the "Run Time Type Information (RTTI)" subchapter of the "Object orientation" chapter in Portabl E's main manual.

5.13. Peek & poke

  PROC GetBool( ptr:PTR TO BOOL ) RETURNS value:BOOL
  PROC GetByte( ptr:PTR TO BYTE ) RETURNS value:BYTE
  PROC GetChar( ptr:PTR TO CHAR ) RETURNS value:CHAR
  PROC GetInt(  ptr:PTR TO INT  ) RETURNS value:INT
  PROC GetLong( ptr:PTR TO LONG ) RETURNS value:LONG
  PROC GetQuad( ptr:PTR TO QUAD ) RETURNS value:QUAD
  PROC GetFloat(ptr:PTR TO FLOAT) RETURNS value:FLOAT
  PROC GetPtr(  ptr:PTR TO PTR  ) RETURNS value:PTR
  PROC GetArray(ptr:PTR TO ARRAY) RETURNS value:ARRAY
  PROC GetValue(ptr:PTR TO VALUE) RETURNS value:VALUE

These procedures peek the given ptr address, and return a value of the requested type.

  PROC PutBool( ptr:PTR TO BOOL , value:BOOL )
  PROC PutByte( ptr:PTR TO BYTE , value:BYTE )
  PROC PutChar( ptr:PTR TO CHAR , value:CHAR )
  PROC PutInt(  ptr:PTR TO INT  , value:INT  )
  PROC PutLong( ptr:PTR TO LONG , value:LONG )
  PROC PutQuad( ptr:PTR TO QUAD , value:QUAD )
  PROC PutFloat(ptr:PTR TO FLOAT, value:FLOAT)
  PROC PutPtr(  ptr:PTR TO PTR  , value:PTR  )
  PROC PutArray(ptr:PTR TO ARRAY, value:ARRAY)
  PROC PutValue(ptr:PTR TO VALUE, value:VALUE)

These procedures poke the provided value into the given ptr address.

5.14. Miscellaneous

  PROC CleanUp(returnValue=0)
  PROC OptMultiThreaded() RETURNS multiThreaded:BOOL
  PROC FileLength(path:ARRAY OF CHAR) RETURNS size   ->depreciated
  PROC KickVersion(version)   ->currently always returns TRUE

CleanUp() exits the program at any point. It was depreciated in AmigaE, but has been reinstated in Portabl E by using the exception system. It throws a negative exception value (which are reserved for use by E).

OptMultiThreaded() returns whether the program used OPT MULTITHREADED or not. This can be used to optimise your general-purpose module, such that it avoids worrying about multi-threading unless it has to.

FileLength() returns the length of the given file, but it's use is depreciated because (1) it is unnecessary due to the 'std/cPath' module, and (2) the path it takes is not truely portable.

KickVersion() is supposed to check whether the current Amiga Kickstart version is >= the supplied version, but currently it always returns TRUE. If someone could tell me how to implement this procedure then it would likely be moved to the 'exec' module.


Go back to CONTENTS


6. Built-in methods

All classes have the following methods:

  METHOD InfoClassType() RETURNS typeof:CLASSTYPE
  METHOD IsSameClassTypeAs(type:CLASSTYPE) RETURNS isSame:BOOL
  METHOD IsOfClassType(parent:CLASSTYPE) RETURNS isSubtype:BOOL

For more information please see the "Run Time Type Information (RTTI)" subchapter of the "Object orientation" chapter in Portabl E's main manual.


Go back to CONTENTS


7. AmigaE procedures that WERE built-in

Some organisational changes have been made from AmigaE to ensure that Portabl E is truely OS independant.

7.1. Dos, Exec, Graphics & Intuition procedures

Procedures for Dos, Exec, Graphics & Intuition are no-longer built-in, and must instead be requested using:

  MODULE 'dos', 'exec', 'graphics', 'intuition'

This happens automatically when the compatibility mode is enabled.

7.2. Graphics & Intuition helper procedures

AmigaE's built-in Graphics helper functions (like Plot() & TextF()) are not available, unless the Amiga 'graphics' module is used, or the compatibility mode is enabled. But they are now depreciated in favour of the 'std/cGfx' module.

AmigaE's built-in Intuition helper functions (like OpenW() & Gadget()) are not available, unless the Amiga 'intuition' module is used, or the compatibility mode is enabled. But they are now depreciated in favour of the 'std/cGui' module.

7.3. arg & wbmessage global variables

The arg variable is not available, unless the Amiga 'dos' module is used, or the compatibility mode is enabled. It would be better to use the ShellArgs() procedure from the 'std/pShell' module.

The wbmessage variable is not available, unless the Amiga 'wb' module is used, or the compatibility mode is enabled.

7.4. Renamed procedures

Please see the "Statements, expressions & functions" subchapter of the "Reversible changes from AmigaE" chapter in the main Portabl E manual for a list of procedures that have been renamed. Although if you look carefully in this documentation you should be able to find them anyway!

Also note that the exceptioninfo variable has been renamed exceptionInfo, unless the compatibility mode is enabled.


Go back to CONTENTS


8. What do the different MODULEs do?

Because the list of MODULEs is quite large, and perhaps it would feel like a lot of effort to read every one until you found the right one, here is a quick explanation of the modules:

Basic stuff:

Commonly needed modules:

More powerful versions of some of the above modules:

Some smaller "sub-modules", if you don't need everything in 'std/cPath':

Obscure or advanced stuff:

Go back to CONTENTS


9. MODULE 'std/pBox'

This module allows you to quickly "box" a value inside of a class object, and then "unbox" it to retrieve that value. The intention is that you use it with set/getDataBox() methods (which expect a "PTR TO class"), so that you can store/retrieve any kind of value.

This module means there is no need for separate getter/setter methods for each type of data.

Supported OSes: All.

9.1. Procedures

  PROC        BoxPTR(data:PTR) RETURNS box:OWNS PTR TO class
  PROC      UnboxPTR(box:PTR TO class)           RETURNS    data:PTR
  PROC ReplaceBoxPTR(box:PTR TO class, data:PTR) RETURNS oldData:PTR
  PROC        BoxARRAY(data:ARRAY) RETURNS box:OWNS PTR TO class
  PROC      UnboxARRAY(box:PTR TO class)             RETURNS    data:ARRAY
  PROC ReplaceBoxARRAY(box:PTR TO class, data:ARRAY) RETURNS oldData:ARRAY
  PROC        BoxSTRING(data:OWNS STRING) RETURNS box:OWNS PTR TO class
  PROC      UnboxSTRING(box:PTR TO class)                   RETURNS    data:     STRING
  PROC ReplaceBoxSTRING(box:PTR TO class, data:OWNS STRING) RETURNS oldData:OWNS STRING
  PROC        BoxLIST(data:OWNS LIST) RETURNS box:OWNS PTR TO class
  PROC      UnboxLIST(box:PTR TO class)                 RETURNS    data:     LIST
  PROC ReplaceBoxLIST(box:PTR TO class, data:OWNS LIST) RETURNS oldData:OWNS LIST
  PROC        BoxVALUE(data:VALUE) RETURNS box:OWNS PTR TO class
  PROC      UnboxVALUE(box:PTR TO class, nilValue=0) RETURNS    data:VALUE
  PROC ReplaceBoxVALUE(box:PTR TO class, data:VALUE) RETURNS oldData:VALUE
  PROC        BoxBIGVALUE(data:BIGVALUE) RETURNS box:OWNS PTR TO class
  PROC      UnboxBIGVALUE(box:PTR TO class, nilValue=0:BIGVALUE) RETURNS    data:BIGVALUE
  PROC ReplaceBoxBIGVALUE(box:PTR TO class, data:BIGVALUE)       RETURNS oldData:BIGVALUE

As the procedures for different types behave similarly, here is a general explanation of each procedure for type FOO where FOO could be PTR, ARRAY, STRING or LIST:

BoxFOO creates & returns a class object which contains the supplied data (of type FOO). NOTE: As hinted by the use of "OWNS", when data is a STRING or LIST, the box takes ownership of it, so it will be destroyed when the box itself is destroyed.

UnboxFOO takes the previously created box, and returns the data (of type FOO) that is stored inside it. The data is still left inside the box, so it can be retrieved again.

UnboxVALUE takes the additional parameter nilValue, which is the value it will return if box is NIL. The other unboxing procedures always return NIL if box is NIL.

ReplaceBoxFOO replaces the oldData stored in the box with the new data supplied by you. The oldData is returned. You can supply NIL/etc as the new data.


Go back to CONTENTS


10. MODULE 'std/pCallback'

This module allows you to call function pointers that are obtained using CALLBACK. It should be considered a hack, which will not be available for target languages like Java, and so should be avoided except when porting existing AmigaE code.

Supported OSes: All (currently!).

10.1. Procedures

  PROC call0empty(func:PTR)
  PROC call0     (func:PTR) RETURNS value
  PROC call0many (func:PTR) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call1empty(func:PTR, p1)
  PROC call1     (func:PTR, p1) RETURNS value
  PROC call1many (func:PTR, p1) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call2empty(func:PTR, p1, p2)
  PROC call2     (func:PTR, p1, p2) RETURNS value
  PROC call2many (func:PTR, p1, p2) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call3empty(func:PTR, p1, p2, p3)
  PROC call3     (func:PTR, p1, p2, p3) RETURNS value
  PROC call3many (func:PTR, p1, p2, p3) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call4empty(func:PTR, p1, p2, p3, p4)
  PROC call4     (func:PTR, p1, p2, p3, p4) RETURNS value
  PROC call4many (func:PTR, p1, p2, p3, p4) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call5empty(func:PTR, p1, p2, p3, p4, p5)
  PROC call5     (func:PTR, p1, p2, p3, p4, p5) RETURNS value
  PROC call5many (func:PTR, p1, p2, p3, p4, p5) RETURNS value, ret2, ret3, ret4, ret5
  
  PROC call6empty(func:PTR, p1, p2, p3, p4, p5, p6)
  PROC call6     (func:PTR, p1, p2, p3, p4, p5, p6) RETURNS value
  PROC call6many (func:PTR, p1, p2, p3, p4, p5, p6) RETURNS value, ret2, ret3, ret4, ret5

Hopefully it's use is fairly self-explanatory:

Go back to CONTENTS


11. MODULE 'std/pShell'

This module provides basic functionality that is usually needed for Shell programs.

Supported OSes: All.

11.1. Constants

  CONST SHELL_RET_OK
  CONST SHELL_RET_WARN
  CONST SHELL_RET_ERROR
  CONST SHELL_RET_FAIL

SHELL_RET_OK can be returned by your main() procedure, to indicate your program finished successfully.

SHELL_RET_WARN can be returned by your main() procedure, to indicate a warning.

SHELL_RET_ERROR can be returned by your main() procedure, to indicate an error.

SHELL_RET_FAIL can be returned by your main() procedure, to indicate a failure.

11.2. Procedures

  PROC ExecuteCommand(command:ARRAY OF CHAR) RETURNS executed:BOOL
  PROC ProgramName() RETURNS progName:ARRAY OF CHAR
  PROC ShellArgs() RETURNS shellArgs:ARRAY OF CHAR
  PROC CtrlC() RETURNS pressed:BOOL

ExecuteCommand() takes a Shell command, and executes it. It returns TRUE if the command could be found & was executed, but this does not indicate whether the command was successful or not. Currently there is no portable way to determine the return value of a command.

While ExecuteCommand() may be portable (i.e. OS independant), the Shell command provided to it is not. Therefore you will need to check the pe_TargetOS variable with StrCmp() to decide what command should be executed.

ProgramName() returns a string containing the name of the program's executable file.

ShellArgs() returns a string containing the parameters passed to your Shell program. This string may be empty if it was not executed as a Shell command. Beware that the spacing between words may not be exactly preserved, so for example several spaces may become just one.

CtrlC() allows your program to determine whether the user has pressed Ctrl-C or not since the last CtrlC() call.

  PROC HighlightOnString()  RETURNS  on:ARRAY OF CHAR
  PROC HighlightOffString() RETURNS off:ARRAY OF CHAR

HighlightOnString() returns a string that can be used to start highlighting (or at least mark) a section of Print()ed text.

HighlightOffString() returns a string that can be used to stop highlighting (or at least mark) a section of Print()ed text.


Go back to CONTENTS


12. MODULE 'std/pShellParameters'

This module provides Amiga-like Shell parameter parsing, but is completely OS independant, and far less error prone than ReadArgs().

Supported OSes: All.

12.1. Example usage

This is how easy it is to use:

  DEF file:ARRAY OF CHAR, quiet:BOOL
  
  IF ParseParams('File/A, Quiet/S') = FALSE THEN Raise("QUIT")
  file  := GetParam(0)
  quiet := GetParam(1) <> NILA

The following example programs use it:

  Examples/std/Shell/AmigaAttributes.e
  Examples/std/Shell/BinDif.e
  Examples/std/Shell/DeleteModuleCache.e
  Examples/std/Shell/PEGCC.e
  Examples/std/Shell/RecursiveDir.e
  Examples/std/Shell/Timer.e

12.2. Procedures

  PROC ParseParams(template:ARRAY OF CHAR, shellArgs=NILA:ARRAY OF CHAR, silent=FALSE:BOOL) RETURNS success:BOOL
  PROC GetParam(index) RETURNS arg:ARRAY OF CHAR
  PROC NumberOfParams() RETURNS numberOfParams

ParseParams() uses the supplied template to parse the parameters provided to your Shell program. If you supply shellArgs then it will parse that instead.

It returns TRUE when the parameters were parsed without error. It returns FALSE when parameters did not match the template, for which an error will have already been reported to the user, so your program should just quit silently. If TRUE was given to silent then no error will be reported to the user.

GetParam() allows you to retrieve one of the parameters supplied to your program. The value of index specifies which parameter you want, with the first parameter being 0. The retrieved parameter is always returned as a string, even if the parameter only accepts numbers. If no such parameter was supplied, then it returns NILA.

NumberOfParams() returns the number of parameters in the template. It can be used to help emulate ReadArgs() if you wish.

12.3. Template guide

Templates are of the form:

  'Parameter1, Parameter2/X, Parameter3=P3/Y'

where P3 is an alternative name for Parameter3, and X & Y are flags. Multiple flags may be used, but each one must have a forward slash before it.

The template flags supported are:

  /A = a required parameter
  /K = the keyword is required
  /S = the parameter is a switch
  /N = the parameter is a number
  /F = the parameter takes the rest of the line

The user's supplied parameters are parsed according to the template. If the user ends their parameters with a question mark, then the template is shown, and the user can enter additional parameters.

Read about AmigaDOS argument passing, which uses ReadArgs(), for a better idea how to use templates.


Go back to CONTENTS


13. MODULE 'std/pStack'

This module allows you to check the stack at run-time.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

These procedures are not currently supported by the Linux & Windows (POSIX) targets, but it isn't needed in those cases anyway.

13.1. Procedures

  PROC FreeStack() RETURNS bytes
  PROC StackSize() RETURNS bytes

FreeStack() returns the approximate number of bytes free in the stack.

StackSize() returns the total number of bytes allocated to the stack.


Go back to CONTENTS


14. MODULE 'std/pSemaphores'

This module provides portable semaphores.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

These procedures are not currently supported by the Windows target, due to MinGW not supporting POSIX semaphores. It's also not supported by the Linux target, as I haven't yet needed it.

14.1. Procedures

  PROC NewSemaphore() RETURNS sem:SEMAPHORE
  PROC DisposeSemaphore(sem:SEMAPHORE) RETURNS nil:SEMAPHORE
  PROC SemLock(sem:SEMAPHORE)
  PROC SemUnlock(sem:SEMAPHORE)
  PROC SemTryLock(sem:SEMAPHORE) RETURNS success:BOOL

NewSemaphore() allocates an e-semaphore.

DisposeSemaphore() deallocates the provided e-semaphore. It returns NIL for convenience.

SemLock() attempts to obtain a lock on the provided sem e-semaphore, and blocks your program until it obtains it.

SemUnlock() unlocks the provided sem e-semaphore.

SemTryLock() is similar to SemLock(), except that it returns FALSE if it can't immediately obtain a lock (instead of blocking).


WARNING: These functions literally do nothing, unless your program has OPT MULTITHREADED at the top. This allows you to write modules that support multi-threading, without needing to suffer semaphore overhead in single-threaded programs.


Go back to CONTENTS


15. MODULE 'std/pTime'

This module provides portable time & date related functions.

Supported OSes: All.

15.1. Example usage

The following example programs use it:

  Examples/Graphics/Clock.e
  Examples/Shell/pTime.e

15.2. Procedures

  PROC CurrentTime(zone0local1utc2quick=0) RETURNS time:BIGVALUE

CurrentTime() returns the current time & date, as the number of seconds which have elapsed since 0:00:00 on 1st January 2000. Times & dates before then are negative values!

It takes a "zone" parameter to specify which timezone it should use. The default value of 0 means return the local time (including DST if appropriate). A value of 1 means return UTC time. A value of 2 means return whatever timezone is quickest to calculate, and should only be used for measuring the length of time periods.


Go back to CONTENTS


16. MODULE 'std/pUnsigned'

This module provides basic support for unsigned number types. Beware that it has some limitations:

Supported OSes: All.

16.1. Example usage

The following example programs use it:

  Examples/std/Shell/crc32.e

16.2. Types

UBYTE is an Unsigned BYTE (8-bits), and is a subtype of RANGE 0 TO 255.

UINT is an Unsigned INT (16-bits), and is a subtype of RANGE 0 TO 65535.

ULONG is an Unsigned LONG (32-bits), and is (somewhat incorrectly) a subtype of LONG (but this means you can use LONG where ULONG is expected, or vice versa, and it will automatically convert the type for you).

UBIGVALUE is an Unsigned BIGVALUE (usually 64-bits), and is (somewhat incorrectly) a subtype of BIGVALUE.

16.3. Procedures

  PROC BigEndianUINT( in:UINT ) RETURNS out:UINT
  PROC BigEndianULONG(in:ULONG) RETURNS out:ULONG
  PROC BigEndianUBIGVALUE(in:UBIGVALUE) RETURNS out:UBIGVALUE
  
  PROC LittleEndianUINT( in:UINT ) RETURNS out:UINT
  PROC LittleEndianULONG(in:ULONG) RETURNS out:ULONG
  PROC LittleEndianUBIGVALUE(in:UBIGVALUE) RETURNS out:UBIGVALUE
  
  PROC SwapEndianUINT( in:UINT ) RETURNS out:UINT
  PROC SwapEndianULONG(in:ULONG) RETURNS out:ULONG
  PROC SwapEndianUBIGVALUE(in:UBIGVALUE) RETURNS out:UBIGVALUE

These are the unsigned equivalents of the existing endian swapping procedures.


Go back to CONTENTS


17. MODULE 'std-alpha/functions'

This module provides standard functions that your functions can inherit. The aim is to allow functions written by one person to be used by algorithms written by another person.

For example, LIST-based implementations of Fmap() & Freduce() are provided, and they will work with any functions that inherit the appropriate standard functions.

Supported OSes: All.

Be warned that this module is still considered an "alpha" version, and therefore may change significantly (or may have major bugs).

17.1. Functions

  FUNC funcParam0empty()
  FUNC funcParam0     () OF funcParam0empty RETURNS value
  FUNC funcParam1empty(p1)
  FUNC funcParam1     (p1) OF funcParam1empty RETURNS value
  FUNC funcParam2empty(p1, p2)
  FUNC funcParam2     (p1, p2) OF funcParam2empty RETURNS value
  FUNC funcParam3empty(p1, p2, p3)
  FUNC funcParam3     (p1, p2, p3) OF funcParam3empty RETURNS value
  FUNC funcParam4empty(p1, p2, p3, p4)
  FUNC funcParam4     (p1, p2, p3, p4) OF funcParam4empty RETURNS value
  FUNC funcParam5empty(p1, p2, p3, p4, p5)
  FUNC funcParam5     (p1, p2, p3, p4, p5) OF funcParam5empty RETURNS value
  FUNC funcParam6empty(p1, p2, p3, p4, p5, p6)
  FUNC funcParam6     (p1, p2, p3, p4, p5, p6) OF funcParam6empty RETURNS value
  FUNC funcParam7empty(p1, p2, p3, p4, p5, p6, p7)
  FUNC funcParam7     (p1, p2, p3, p4, p5, p6, p7) OF funcParam7empty RETURNS value
  FUNC funcParam8empty(p1, p2, p3, p4, p5, p6, p7, p8)
  FUNC funcParam8     (p1, p2, p3, p4, p5, p6, p7, p8) OF funcParam8empty RETURNS value

For more information please see the "Functional programming" chapter of the main Portabl E manual.

17.2. Procedures

  PROC Fmap(function:PTR TO funcParam1, list:LIST)
  PROC Freduce(function:PTR TO funcParam2, list:ILIST, init)

For more information please see the "Functional programming" chapter of the main Portabl E manual.


Go back to CONTENTS


18. MODULE 'std/cAppSimple'

Use this module instead of the cApp module, to simplify things for beginners.

This module is used to describe your program (Application) to the OS in a portable way. It is needed by several other modules (such as cGfx & cGui) so that they can work together (otherwise cGfx windows would seem to come from a different program to the cGui windows!).

Supported OSes: The same as cApp.


18.1. Example usage

The simplest use of this module would be:

  IsDesktopApp()

If you wanted your window to fully cover the screen:

  IsFullWindowApp()

If you wanted your own screen:

  IsFullScreenApp(640, 480)

18.2. Procedures

One of the following procedures must be called before you open any windows (using cGfx or cGui). You must not call more than one procedure. Typically you would call it at the start of your program.

  PROC IsDesktopApp(   title=NILA:ARRAY OF CHAR)
  PROC IsFullWindowApp(title=NILA:ARRAY OF CHAR)
  PROC IsFullScreenApp(width, height, title=NILA:ARRAY OF CHAR)

IsDesktopApp() indicates that your program will appear on the computer's desktop (called Workbench on Amiga). You can supply a title (i.e. name) for your program, otherwise your executable's file name will be used. This must be called before opening any windows!

IsFullWindowApp() indicates that your program will have a window that takes up the whole screen. Typically used by 'serious' applications. You can supply a title (i.e. name) for your program, otherwise your executable's file name will be used. This must be called before opening any windows!

IsFullScreenApp() indicates that your program will use the whole screen, without any window borders. You must supply the width & height of the screen. Typically used by games. You can supply a title (i.e. name) for your program, otherwise your executable's file name will be used. This must be called before opening any windows!


Go back to CONTENTS


19. MODULE 'std/cApp'

This module is used to describe your program (Application) to the OS in a portable way. It is needed by several other modules (such as cGfx & cGui) so that they can work together (otherwise cGfx windows would seem to come from a different program to the cGui windows!).

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

19.1. Example usage

The simplest use of this module would be:

  CreateApp().build()

A better use of this module might look like this:

  CreateApp('my program name').initVersion('v1.0').initDescription('a cliched demo').build()

It is not usually necessary, but you can also do this:

  DEF app:PTR TO cApp
  
  app := CreateApp('my program name')
  app.initVersion('v1.0')
  app.initDescription('a cliched demo')
  app.build()

19.2. Procedures

  PROC CreateApp(title=NILA:ARRAY OF CHAR) RETURNS app:PTR TO cApp
  PROC DestroyApp()
  PROC MinimiseApp(undo=FALSE:BOOL)

CreateApp() creates & returns a cApp object that will represent your Application. You can supply a title (i.e. name) for your program, otherwise your executable's file name will be used. You should then use it's methods (see below) to describe your program, before finally building it. You are only allowed to create one cApp object!

DestroyApp() destroys your cApp object. Since there can only ever be one cApp object, you do not need to supply it. It will also destroy any resources that depend on it, such as open windows. Since it is automatically called when your program quits, you don't normally need to use it!

Since DestroyApp() is automatically called when your program quits, any open windows (and other resources) will also be automatically closed.

MinimiseApp() minimises your Application, or undoes minimisation when you supply TRUE for undo. The actual behaviour depends on the OS, but on AmigaOS it will cause MUI windows to be iconified (while cGfx windows are currently unaffected).

19.3. Methods of cApp

  /* Methods of cApp */
  METHOD initVersion(    info:ARRAY OF CHAR) RETURNS self:PTR TO cApp
  METHOD initCopyright(  info:ARRAY OF CHAR) RETURNS self:PTR TO cApp
  METHOD initAuthor(     info:ARRAY OF CHAR) RETURNS self:PTR TO cApp
  METHOD initDescription(info:ARRAY OF CHAR) RETURNS self:PTR TO cApp
  METHOD initFullWindow()                    RETURNS self:PTR TO cApp
  METHOD initFullScreen(width, height)       RETURNS self:PTR TO cApp
  METHOD build()

initVersion() sets a string that gives your program's version. This must be called before the App is built.

initCopyright() sets a string that gives your program's copyright information. This must be called before the App is built.

initAuthor() sets a string that gives your program's author (names). This must be called before the App is built.

initDescription() sets a string that gives a short description of your program's purpose. This must be called before the App is built.

initFullWindow() indicates that your program should have a window that takes up the whole screen. This must be called before the App is built. Typically used by 'serious' applications. You cannot use this with initFullScreen()!

initFullScreen() indicates that your program should use the whole screen, without any window borders. You must supply the width & height of the screen. This must be called before the App is built. Typically used by games. You cannot use this with initFullWindow()!

build() causes your Application to be built according to the information already given. So it should be called after using any init methods that you need. Other modules canNOT use cApp until it has been built!

  /* more methods of cApp */
  METHOD infoTitle()       RETURNS info:ARRAY OF CHAR
  METHOD infoVersion()     RETURNS info:ARRAY OF CHAR
  METHOD infoCopyright()   RETURNS info:ARRAY OF CHAR
  METHOD infoAuthor()      RETURNS info:ARRAY OF CHAR
  METHOD infoDescription() RETURNS info:ARRAY OF CHAR
  METHOD infoFullWindow()  RETURNS fullWindow:BOOL
  METHOD infoFullScreen()  RETURNS fullScreen:BOOL, width, height

infoTitle() returns the title you set using the CreateApp() procedure.

infoVersion() returns the version you set using the initVersion() method, or NILA if none was set.

infoCopyright() returns the copyright you set using the initCopyright() method, or NILA if none was set.

infoAuthor() returns the author you set using the initAuthor() method, or NILA if none was set.

infoDescription() returns the description you set using the initDescription() method, or NILA if none was set.

infoFullWindow() returns whether you used the initFullWindow() method or not.

infoFullScreen() returns whether you used the initFullScreen() method or not. It also returns the width & height of the screen you set.

  /* more methods of cApp */
  METHOD minimise(undo=FALSE:BOOL)

minimise() has the same effect as the MinimiseApp() procedure.


Go back to CONTENTS


20. MODULE 'std/cGfxSimple'

This module is the same as the cGfx module (which provides pixel-based graphics), except that it provides a few extras to simplify things for beginners. Those extras are detailed below.

Beware that you canNOT use this module at the same time as the cGfxSpritesSimple module, to draw within the same window. Use one or the other, but not both at the same time.

Supported OSes: The same as cGfx.

20.1. Example usage

How to open a window:

  IsDesktopApp()	->you only need to do this once!
  OpenWindow(640, 480)

How to draw in the window:

  SetColour(RGB_ORANGE)
  DrawBox( 20,20, 50,50)
  
  SetColour(RGB_BLACK)
  DrawText(20,20, 'Hello world!')

Here is one way to show a picture in the window:

  StoreBitmap('player', 0, LoadPicture('spaceship.gif'))
  UseBitmap('player', 0).draw(50,50)

Or you could do this:

  StoreBitmap('player', 0, LoadPicture('spaceship.gif'))
  LastBitmap().draw(50,50)

Here's another way to show a picture in the window:

  DEF player:PTR TO cGfxBitmap
  
  player := LoadPicture('spaceship.gif')
  player.draw(50,50)

The following example programs use it:

  Examples/std/Graphics/Clock.e
  Examples/std/Graphics/Cosmic/cosmic_deluxe.e
  Examples/std/Graphics/IfsFern.e
  Examples/std/Graphics/Mandel.e
  Examples/std/Graphics/Pythagoras.e
  Examples/std/Graphics/StarsXY.e
  Examples/std/Graphics/StarsZ.e
  Examples/std/Graphics/StarsZYX.e
  Examples/std/Graphics/ToySketch.e
  Examples/std/Multimedia/ShadowOfTheBlitz_Scroller/sotb_orig.e
  Examples/std/Multimedia/StarsDemo.e

Released programs which are known to use it:

  HueFlow          ( os4depot.net/?function=showfile&file=game/puzzle/hueflow.lha )
  Ami-Scratch      ( os4depot.net/?function=showfile&file=graphics/misc/amiscratch.lha )
  Ami-Bootguard    ( os4depot.net/?function=showfile&file=utility/misc/ami-bootguard.lha )
  Ami-Lineapolis   ( www.lineapolis.dizzy.pl )

20.2. Details

You do not need to use CreateGfxWindow(), because it is automatically called, with the result stored in the gfx global variable.

The 'std/cAppSimple' module is automatically available, so you can use it's procedures if you want.

The following RGB constants are provided for use with SetColour():

  RGB_WHITE,  RGB_BLACK,   RGB_GRAY, RGB_GREY, RGB_SILVER, 
  RGB_RED,    RGB_GREEN,   RGB_BLUE, 
  RGB_YELLOW, RGB_MAGENTA, RGB_CYAN, 
  RGB_ORANGE, RGB_PURPLE,  RGB_PINK, RGB_BROWN

20.3. Procedures

  PROC LastBitmap() RETURNS bitmap:PTR TO cGfxBitmap
  PROC ChangeGfxWindow(title=NILA:ARRAY OF CHAR, hideMousePointer=FALSE:BOOL, enableAlphaChannel=FALSE:BOOL)

LastBitmap() gives you the last bitmap that was returned by one of the following procedures. If there was no last bitmap, then it protects you by throwing an exception.

ChangeGfxWindow() allows you to give a title (i.e. name) for your window. If you give TRUE for hideMousePointer then the mouse pointer will not be visible for the window. But you can only make these changes before opening the window!

If you give TRUE for enableAlphaChannel then loadPicture() will load the alpha-channel of a picture, if the OS supports it. infoAlphaChannel() will return TRUE if the OS supports it (and it has been enabled).

By default alpha-channel support is disabled in the 'std/cGfxSimple' module, so you need to call ChangeGfxWindow() to enable it.

  PROC InfoScreenWidth()  RETURNS width
  PROC InfoScreenHeight() RETURNS height
  PROC OpenWindow(width, height, resizable=FALSE:BOOL)
  PROC OpenFull()
  PROC CloseWindow()
  PROC CloseFull()
  PROC GetPosition() RETURNS x, y
  PROC SetPosition(x, y)
  PROC InfoWidth()  RETURNS width
  PROC InfoHeight() RETURNS height
  PROC ChangeSize(width, height)
  PROC SetFrameSkipping(frameSkipping:BOOL)
  PROC SetAutoUpdate(autoUpdate:BOOL)
  PROC UpdateAndWaitForScreenRefresh() RETURNS skippingNextFrame:BOOL
  PROC WaitForScreenRefresh()
  PROC Clear(rgb)
  PROC SetColour(rgb)
  PROC GetColour() RETURNS rgb
  PROC SetColor(rgb)
  PROC GetColor()  RETURNS rgb
  PROC ReadDot(x, y) RETURNS rgb
  PROC DrawDot(x, y)
  PROC DrawLine(x1, y1, x2, y2, thickness=1)
  PROC DrawBox(x, y, width, height, unfilled=FALSE:BOOL)
  PROC DrawCircle(x, y, radius,     unfilled=FALSE:BOOL)
  PROC SetFont(name:ARRAY OF CHAR, size, style0plain1underlined2bold4italic=0) RETURNS success:BOOL
  PROC GetFont() RETURNS name:ARRAY OF CHAR, size, style
  PROC DrawText( x, y, fmtString:ARRAY OF CHAR, arg1=0, ..., arg8=0)
  PROC DrawTextL(x, y, fmtString:ARRAY OF CHAR, args=NILL:ILIST, backgroundColour=-1)
  PROC InfoSizeOfTextL(fmtString:ARRAY OF CHAR, args=NILL:ILIST) RETURNS width, height
  PROC ScrollBox(dx, dy, x, y, width, height)
  PROC GetLastEvent() RETURNS type, subType, value, value2
  PROC InfoScreenFPS() RETURNS fps
  PROC StoreBitmap(name:ARRAY OF CHAR, number, bitmap:PTR TO cGfxBitmap) RETURNS storedBitmap:PTR TO cGfxBitmap
  PROC UseBitmap(  name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS bitmap:PTR TO cGfxBitmap
  PROC DestroyBitmap(bitmap:PTR TO cGfxBitmap) RETURNS nil:PTR TO cGfxBitmap
  PROC LoadPicture(file:ARRAY OF CHAR, maskFile=NILA:ARRAY OF CHAR, maskColour=-1) RETURNS pic:PTR TO cGfxBitmap
  PROC ExtractBitmap(x, y, width, height, notDrawable=FALSE:BOOL) RETURNS copy:PTR TO cGfxBitmap
  PROC MakeFractalBitmap(size, pen255colour, pen0colour, roughness=0, maskBelowPen=0, seed=0) RETURNS fractal:PTR TO cGfxBitmap

These are the same as cGfxWindows's methods (see chapter 21.3. Methods of cGfxWindow), but they look simpler because they are procedures. Only the most important methods are available as procedures, and unlike the methods they start with a capital letter.

If LoadPicture() could not load a picture, then it it protects you by throwing an exception.

(Note that both the CloseWindow() & CloseFull() procedures are the same as the close() method. And that the DestroyBitmap() procedure is essentially the same as the destroyDrawable() method.)


Don't forget the procedures from 21. MODULE 'std/cGfx'.


Go back to CONTENTS


21. MODULE 'std/cGfx'

This module provides fairly easy pixel-based graphics, which is suitable for games, animation & multimedia. It is intended to be nearly as easy as AMOS, but more powerful.

Please note that many more features are planned for the future.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

21.1. Example usage

The simplest way to open a window:

  DEF win:PTR TO cGfxWindow
  
  CreateApp().build()		->you only need to do this once!
  win := CreateGfxWindow('demo')
  win.openWindow(640, 480)

How you open a full-screen window:

  DEF win:PTR TO cGfxWindow, width, height
  
  CreateApp().initFullWindow().build()
  win := CreateGfxWindow('demo')
  win.openFull()
  width  := win.infoWidth()
  height := win.infoHeight()

The simplest way to draw in the window:

  win.setColour($FF8800)	->sets Red to $FF, Green to $88, and Blue to $00, giving an orange colour
  win.drawBox( 20,20, 50,50)
  
  win.setColour($000000)
  win.drawText(20,20, 'Hello world!')

How to do flicker-free (double buffered) drawing in the window:

  DEF x
  
  win.setAutoUpdate(FALSE)	->THIS IS IMPORTANT
  win.setColour($FF8800)
  FOR x := 0 TO win.infoWidth()
  	win.clear($808080)
  	win.drawBox(x,20, 50,50)
  	win.updateAndWaitForScreenRefresh()	->THIS IS IMPORTANT
  ENDFOR

How to show a picture in the window:

  DEF pic:PTR TO cGfxBitmap
  
  pic := win.loadPicture('myPicture.gif')
  pic.draw(20,20)

How to handle events from a single open window:

  DEF quit:BOOL, type, subType, value, value2
  
  quit := FALSE
  REPEAT
  	IF WaitForGfxWindowEvent() = win
  		type, subType, value, value2 := win.getLastEvent()
  		
  		IF type = EVENT_WINDOW
  			IF subType = EVENT_WINDOW_CLOSE THEN quit := TRUE
  			
  		ELSE IF type = EVENT_KEY
  			IF subType = EVENT_KEY_ASCII
  				win.setColour($FF0000)
  				win.drawTextL(50, 50, 'You pressed the "\c" key.', [value], $808080)
  			ENDIF
  		ENDIF
  	ENDIF
  UNTIL quit
  win.close()

The following example programs use it:

  Examples/std/Graphics/StarsXY_ToySpaceshipSprite1.e
  Examples/std/Graphics/StarsZYX_ToySpaceshipSprite1.e
  Examples/std/Multimedia/StarsDemo.e

21.2. Procedures

  PROC  CreateGfxWindow(title:ARRAY OF CHAR, hideMousePointer=FALSE:BOOL, enableAlphaChannel=FALSE:BOOL) RETURNS win:PTR TO cGfxWindow
  PROC DestroyGfxWindow(win:PTR TO cGfxWindow) RETURNS nil:PTR TO cGfxWindow
  PROC MakeRGB(red, green, blue) RETURNS rgb
  PROC Pause(delayInTenthsOfSecond)
  PROC  WaitForGfxWindowEvent() RETURNS win:PTR TO cGfxWindow, type, subType, value, value2
  PROC CheckForGfxWindowEvent(keepPreviousEvents=FALSE:BOOL) RETURNS win:PTR TO cGfxWindow, type, subType, value, value2

CreateGfxWindow() creates & returns a cGfxWindow object for a new graphics window. You must supply a title (i.e. name) for your window. If you give TRUE for hideMousePointer then the mouse pointer will not be visible for the window. The window starts off closed, so you must use a method to open it. You can create as many windows as you want!

If you give TRUE for enableAlphaChannel then loadPicture() will load the alpha-channel of a picture, if the OS supports it. infoAlphaChannel() will return TRUE if the OS supports it (and it has been enabled).

DestroyGfxWindow() destroys the supplied window. It will also destroy any resources that depend on it, such a bitmaps. Your windows will be automatically destroyed when your program quits, so you may not need to use this! You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

MakeRGB() returns an RGB value made of the supplied red, green & blue components. They must each be in the range 0 to 255 (inclusive).

Pause() waits for the delay given in 1/10th of a second. So 10 is one second.

WaitForGfxWindowEvent() waits for an event from any window. It then returns the window that the event came from, and also values that describe the event. Please see the 21.6. Events sub-chapter. You don't have to store the event values, as they can be retrieved from the window using the getLastEvent() method. Note WaitForGfxWindowEvent() does not clear the last event from other windows.

Also note that it will only remember the most recent events (typically the last 100), so ensure that you watch for events regularly.

CheckForGfxWindowEvent() checks whether any event has occured yet, and returns it if it has. But if no event has happened, then it returns NIL for win. This method DOES clear the last event from all others windows, unless you supplied TRUE for keepPreviousEvents.

21.3. Methods of cGfxWindow

The cGfxWindow class is a window in which you can draw graphics. The window has a "current drawing colour", which is used by some drawing methods.

Unlike some graphical systems, it does NOT have a "background drawing colour", nor does it have a "current drawing position" (because these were felt to either be unnecessary, or else more of a hiderance than a help).

  /* Methods of cGfxWindow */
  METHOD infoScreenWidth()  RETURNS width
  METHOD infoScreenHeight() RETURNS height
  METHOD openWindow(width, height, resizable=FALSE:BOOL)
  METHOD openFull()
  METHOD close()
  METHOD infoIsOpen() RETURNS isOpen:BOOL
  METHOD infoTitle()  RETURNS title:ARRAY OF CHAR
  METHOD infoAlphaChannel() RETURNS alphaChannelEnabled:BOOL
  METHOD getPosition() RETURNS x, y
  METHOD setPosition(x, y)
  METHOD infoWidth()  RETURNS width
  METHOD infoHeight() RETURNS height
  METHOD changeSize(width, height)

infoScreenWidth() & infoScreenHeight() return the size of the main screen. You can use them to decide what size window you should open.

openWindow() opens a window of the given size. If you use TRUE for resizable then the user will be allowed to resize the window (you will get an EVENT_WINDOW_RESIZED event when that happens). You may not use this method if the initFullWindow() or initFullScreen() methods were used on cApp.

openFull() opens a full window/screen, as previously specified by the initFullWindow() or initFullScreen() method that MUST have been used on cApp.

close() closes the window, loosing whatever was drawn in it. An exception will be thrown if the window is not open.

infoIsOpen() returns whether the window is open or not.

infoTitle() returns the title you set using the CreateGfxWindow() procedure.

infoAlphaChannel() returns whether alpha-channel support is enabled.

getPosition() return the position of the window.

setPosition() changes the position of the window. This can be done before the window is opened.

infoWidth() & infoHeight() return the size of the window.

changeSize() changes the size of the window, and cause an EVENT_WINDOW_RESIZED event (the same as when a user resizes the window).

NOTE: That on AmigaOS the window's size may not actually change for up to 0.1 seconds (i.e. 6 frames). You can find out when it has actually changed by checking for an EVENT_WINDOW_RESIZED event.

  /* more methods of cGfxWindow */
  METHOD getFrameSkipping() RETURNS frameSkipping:BOOL
  METHOD setFrameSkipping(frameSkipping:BOOL)
  METHOD setAutoUpdate(autoUpdate:BOOL)
  METHOD getAutoUpdate() RETURNS autoUpdate:BOOL
  METHOD updateAndWaitForScreenRefresh() RETURNS skippingNextFrame:BOOL
  METHOD infoSkippingNextFrame()         RETURNS skippingNextFrame:BOOL
  METHOD waitForScreenRefresh()

getFrameSkipping() & setFrameSkipping() allow you to change & retrieve whether or not the window has frame skipping enabled. For frame skipping to work, it also needs auto-update to be disabled. Typically a new window defaults to FALSE for frameSkipping, which means that all frames will be displayed. With it set to TRUE, it will skip frames which have been missed. That means your program should run at the same speed on slower machines, but it can cause jerkiness due to the skipping of frames.

Note that on AROS frameSkipping defaults to TRUE, because AROS is usually run under emulation, and that is far too slow for a 60Hz frame rate.

setAutoUpdate() & getAutoUpdate() allow you to change & retrieve the window's auto-update mode. A new window defaults to TRUE for autoUpdate, which means that all changes to the window contents are immediately visible, although this can sometimes cause flickering. When autoUpdate is FALSE, no changes are shown in the window until the updateAndWaitForScreenRefresh() method is called, which allows you to have silky smooth graphics.

updateAndWaitForScreenRefresh() waits for the screen to have completed refreshing, before updating it with any changes you have made to the contents of the window. This is done using a double buffer, giving you "vsynced" graphics. AutoUpdate must have been disabled, or an exception will be thrown.

Normally it returns FALSE, but if it detects a screen refresh has been missed (and frame skipping is enabled), then it will return TRUE to indicate that it will automatically skip the next frame, to keep your program/game running smoothly. You can safely ignore this, but if you wish to optimise your program, then you can avoid doing any CPU or graphically intensive operations that are only needed for the next frame.

infoSkippingNextFrame() returns the same value as the last updateAndWaitForScreenRefresh() method call did.

waitForScreenRefresh() waits for the screen to have completed refreshing.

  /* more methods of cGfxWindow */
  METHOD clear(rgb)
  METHOD setColour(rgb)
  METHOD getColour() RETURNS rgb
  METHOD setColor(rgb)
  METHOD getColor()  RETURNS rgb
  METHOD readDot(x, y) RETURNS rgb

clear() fills the entire contents of the window with the given colour. The current draw colour is unaffected.

setColour() sets the current draw colour to the given RGB value.

getColour() returns the current draw colour.

setColor() is the same as setColour().

getColor() is the same as getColour().

readDot() returns the colour of the pixel at x,y.

  /* more methods of cGfxWindow */
  METHOD drawDot(x, y)
  METHOD drawLine(x1, y1, x2, y2, thickness=1)
  METHOD drawBox(x, y, width, height, unfilled=FALSE:BOOL)
  METHOD drawCircle(x, y, radius,     unfilled=FALSE:BOOL)

drawDot() draws a dot at position x,y using the current draw colour. Note that position 0,0 is the top left of the window.

drawLine() draws a line between position x1,y1 and x2,y2 using the current draw colour. The line has a width of 1 unless thickness is given. If the line goes outside of the drawable region then it is automatically clipped.

NOTE: Please beware that lines with a thickness>1 may not be exactly identical on different OSes.

drawBox() draws a rectangle, with the top left at the position x,y and with the given width & height (which must be not be negative). The rectangle is filled unless unfilled is TRUE. If the rectangle goes outside of the drawable region then it is automatically clipped.

drawCircle() draws a circle with centre at the position x,y and with the given radius (which must not be negative). The circle is filled, unless unfilled is TRUE. If the circle goes outside of the drawable region then it is automatically clipped.

  /* more methods of cGfxWindow */
  METHOD drawText( x, y, fmtString:ARRAY OF CHAR, arg1=0, ..., arg8=0)
  METHOD drawTextL(x, y, fmtString:ARRAY OF CHAR, args=NILL:ILIST, backgroundColour=-1)
  METHOD setFont(name:ARRAY OF CHAR, size, style0plain1underlined2bold4italic=0) RETURNS success:BOOL
  METHOD getFont() RETURNS name:ARRAY OF CHAR, size, style

drawText() draws the fmtString text, with the top left at the position x,y. The text may contain formatting commands, the same as Print(), and any required parameters will be taken from arg1, etc. The drawn text's background is effectively transparent, so you may first need to clear the area where it will be drawn.

  e.g. win.drawText(20,20, '\d + \d = \d\n', 1, 2, 3)

drawTextL() is similar to drawText(), except that any parameters required for formatted text will be taken from a supplied list. Unlike drawText() you can give a background colour, in which case the background will not be transparent (which on Amiga will be drawn much more efficiently, and can be anti-aliased).

  e.g. win.drawTextL(20,20, '\d + \d = \d\n', [1, 2, 3])

setFont() allows you to change the current font, size & style used by drawText() & drawTextL(). If the named font is found then it will return TRUE. If the named font did not exist then it will return FALSE, and the current font will be unchanged. The plain style is 0, add 1 for underlining, add 2 for bold, and add 4 for italics. setFont() can be a slow operation if the specified size of font is not already in memory.

  e.g. win.setFont('Times', 10)

getFont() returns the current font, size & style.

  /* more methods of cGfxWindow */
  METHOD makeText( fmtString:ARRAY OF CHAR, arg1=0, ..., arg8=0) RETURNS text:PTR TO cGfxDrawable
  METHOD makeTextL(fmtString:ARRAY OF CHAR, args=NILL:ILIST, backgroundColour=-1) RETURNS text:PTR TO cGfxDrawable
  METHOD makeBitmapTextL(fmtString:ARRAY OF CHAR, args=NILL:ILIST, backgroundColour=-1, notDrawable=FALSE:BOOL) RETURNS text:PTR TO cGfxBitmap
  METHOD infoSizeOfTextL(fmtString:ARRAY OF CHAR, args=NILL:ILIST) RETURNS width, height

makeText() & makeTextL() are similar to the drawText() & drawTextL() methods, except that they return an object that can be used to repeatedly draw the text (at any position & any time). Using the draw() method of this object is exactly the same as using the window's drawText() method, except that it uses the colour & font that were 'current' when the object was created. Since the text is stored as a plain string, it is slower but more memory efficient than the makeBitmapTextL() method. You must use destroyDrawable() or END on the returned object when you no-longer need it.

makeBitmapTextL() is similar to the drawTextL() method, except that it draws the text into the bitmap which is returned. Using the draw() method of this bitmap will draw it in the window, just as if you had called the drawTextL() method. The behaviour is exactly the same as for the makeTextL() method, but it stores the text as a graphical bitmap instead of a string. This makes drawing it much faster, but it uses more memory. You must use destroyDrawable() or END on the returned object when you no-longer need it.

infoSizeOfTextL() this returns the size of the object you would get from the makeTextL() or makeBitmapTextL() method, without the need to create it. It is also the effective size of the text drawn by the drawTextL() method. It allows you efficiently modify the text, to get exactly the needed size, before you make or draw the text.

  /* more methods of cGfxWindow */
  METHOD setDrawableRegion(x=0,y=0, width=-1,height=-1)
  METHOD getDrawableRegion() RETURNS x, y, width, height
  METHOD scrollBox(dx, dy, x, y, width, height)
  METHOD getLastEvent() RETURNS type, subType, value, value2
  METHOD setLastEvent(type, subType, value=0, value2=0)

setDrawableRegion() allows you to change the drawable region, which is usually the whole of the window. Any subsequent drawing won't make any changes outside of the drawable region. This can be very useful if you want to have different parts of the window used for different purposes, such as the game world & the status bar. If width/height is set to -1 then the right/bottom of the drawable region is set to the edge of the window.

getDrawableRegion() returns the current drawable region.

scrollBox() scrolls the area inside the given box by dx,dy pixels. If the box is outside of the drawable region then it is automatically clipped.

getLastEvent() returns the last event (for this window) that was returned by the WaitForGfxWindowEvent() or CheckForGfxWindowEvent() procedure. If there were no events, then it returns EVENT_NONE for type.

setLastEvent() allows you to fake (or clear) the last event.

  /* more methods of cGfxWindow */
  METHOD startTimer(periodInMilliSeconds=0)
  METHOD stopTimer()
  METHOD infoPeriodOfTimer() RETURNS periodInMilliSeconds
  METHOD infoScreenFPS() RETURNS fps

startTimer() starts a timer which repeats every periodInMilliSeconds thousandths of a second. When the timer runs out, it will generate an event with type=EVENT_TIMER & subType=EVENT_TIMER_EXPIRED. The event's value is the count of the number of times that the event has expired, since the last timer event was reported (normally this will be 1 unless you don't check events often enough).

stopTimer() stops the timer.

infoPeriodOfTimer() returns the period of the timer in thousandths of a second, or 0 if no timer is running.

infoScreenFPS() returns the screen's Frames Per Second, also known as it's refresh rate in Hertz. Use this to convert a desired delay (in seconds) into a delay of a whole number of frames, so that you can update something smoothly on screen. Beware that the first call to this method may pause your program for around a second, while it measures the screen's FPS.

  /* more methods of cGfxWindow */
  METHOD loadPicture(file:ARRAY OF CHAR, maskFile=NILA:ARRAY OF CHAR, maskColour=-1, notDrawable=FALSE:BOOL) RETURNS pic:PTR TO cGfxBitmap
  METHOD extractBitmap(x, y, width, height, notDrawable=FALSE:BOOL) RETURNS copy:PTR TO cGfxBitmap
  METHOD makeFractalBitmap(size, pen255colour, pen0colour, roughness=0, maskBelowPen=0, seed=0) RETURNS fractal:PTR TO cGfxBitmap
  METHOD storeBitmap(name:ARRAY OF CHAR, number, bitmap:PTR TO cGfxBitmap) RETURNS storedBitmap:PTR TO cGfxBitmap
  METHOD useBitmap(  name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS bitmap:PTR TO cGfxBitmap
  METHOD destroyDrawable(drawable:PTR TO cGfxDrawable, force=FALSE:BOOL) RETURNS nil:PTR TO cGfxDrawable

loadPicture() loads the given picture, and returns a bitmap that can be used to draw the picture in the window. The file path must be given in the portable format used by the cPath module, so you may need to use it's ImportFilePath() procedure first.

If the picture has a mask then this will be used. Alternatively, you can use another file as the mask, in which case maskColour chooses the transparent colour. If you want to use the picture itself as the mask, then just use '' for maskFile.

When maskColour is -1 it uses the top-left pixel's colour, otherwise maskColour indicates the palette number or RGB value (depending on whether the picture has a depth <= 8 or not). Typically you would use 0 for maskColour.

Normally the bitmap is stored in video memory, and so can be drawn into the window. But if you wish to save video memory then give TRUE for notDrawable.

extractBitmap() creates & returns a bitmap containing part of the window. x,y gives the top left corner of the new bitmap, and width,height gives the size of the new bitmap. If you try to copy beyond the edge of the window then an exception will be thrown.

Beware that this can be quite slow, especially if width & height are large.

Normally the bitmap is stored in video memory, and so can be drawn into the window. But if you wish to save video memory then give TRUE for notDrawable.

makeFractalBitmap() creates & returns a bitmap containing a randomly generated 'cloud' or 'terrain' fractal. It can be very useful as a 'background' bitmap, since it tiles perfectly.

size gives the width & heigth of the bitmap, but if it isn't a power of two then it will be rounded-up to one. For example, if you supply 500 for size, then you will get a bitmap which is 512 by 512 pixels.

The bitmap effectively has a depth of 8-bits, since it contains 256 colours. pen255colour gives the RGB value of the highest pen colour, while pen0colour gives the lowest pen colour. The rest of the pen colours change smoothly between those two. For example, if you gave white for pen255colour & black for pen0colour, then you would get various shades of gray for the rest of the colours. For example, you might give a light & a dark shade of green to create a "grass bitmap":

  win.makeFractalBitmap(size, $006000, $004000, 8)

Or give red & orange to create a "lava bitmap":

  win.makeFractalBitmap(size, $FF0000, $FF6000)

roughness is value between 0 & 10 (inclusive) which controls how un-smooth the colour changes are. 0 is very smooth, while 10 is completely random. Values above 8 are unlikely to be useful!

maskBelowPen gives the pen number below which the bitmap is transparent. (It will also cause "pen0colour" to be the last non-transparent colour (so you are still giving the whole visible colour range).) For example, you could use it to make a whitish "cloud bitmap" which has gaps betweens clouds:

  win.makeFractalBitmap(size, $606060, $E0E0E0, 0, 128)

seed allows you to give a particular random number seed, which will always give the same bitmap (even on different Portabl E targets!). This allows you to search for a good looking fractal bitmap, which you can then easily recreate (rather than having to save it for future use).

storeBitmap() & useBitmap() allow you to store & retrieve bitmaps using a name string, and optionally a number. The string must be an 'immediate string', not one you have created. It returns the stored bitmap, so you can use it straight away. Here's an example of how you might use it:

  IF win.storeBitmap('player', 0, win.loadPicture('spaceship.gif')) = NIL THEN Print('Failed to load picture.\n')
  
  win.useBitmap('player', 0).draw(x,y)

If you try to store more than one bitmap with the same name & number combination, then an exception will be raised. This is to prevent you accidentally reusing them. And if you try to use a non-existant bitmap, then an exception will be raised; unless you gave TRUE for allowReturnNIL, in which case NIL will be returned.

destroyDrawable() takes the given bitmap/drawable & destroys it. You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

For safety it will NOT destroy a bitmap/etc if it is being used by another object (such as a sprite), UNLESS you give TRUE for force, as this would normally cause a crash.

  /* more methods of cGfxWindow */
  METHOD queryExtra(specific:QUAD) RETURNS value, unknown:BOOL
  METHOD registerForResizes(  client:PTR TO cGfxNotifyOfWindowResize)
  METHOD unregisterForResizes(client:PTR TO cGfxNotifyOfWindowResize)

queryExtra() allows you to retrieve OS-specific information. For example, if you give "WIND", then it will return the Amiga window pointer. And "SCRN" will return the Amiga screen pointer. Please only use this method as a last resort, because it will stop your code from being portable!

registerForResizes() & unregisterForResizes() are used to tell this window when another object needs to know that it has been resized. You do not normally need to use these methods! (This is used by the cGfxStack class to redraw itself when it's window is resized.)

Note that any sub-class of cGfxNotifyOfWindowResize should implement this method:

  windowHasResized(oldWidth, oldHeight)

21.4. Methods of cGfxDrawable

cGfxDrawable is an abstract class for any fixed-size object that can be drawn inside a window. It does not have to be a bitmap, and can use any window draw methods. You can easily create your own sub-classes of cGfxDrawable, please see the 21.7. Creating your own cGfxDrawable sub-class sub-chapter.

  /* Methods of cGfxDrawable */
  METHOD infoWidth()  RETURNS width
  METHOD infoHeight() RETURNS height
  METHOD infoWindow() RETURNS win:PTR TO cGfxWindow
  METHOD infoIsTransparent() RETURNS isTransparent:BOOL
  METHOD draw(x, y)
  METHOD drawTiled(x, y, tileX:BOOL, tileY:BOOL)

infoWidth() & infoHeight() return the size of the drawable object.

infoWindow() returns the cGfxWindow that this object draws to.

infoIsTransparent() returns whether or not it is (partially) transparent. In the case of a bitmap, this would mean it has a mask.

draw() draws the object at the given position.

drawTiled() is the same as draw(), but it allows the object to be horizontally or vertically tiled, so it appears to be infinitely wide (when tileX is TRUE) and/or infinitely tall (when tileY is TRUE). When tiled, the drawable will be repeated in a 'tiled' fashion, thus allowing you to easily have background(s) that go on 'forever'.

The following methods are for advanced users only:

  /* more methods of cGfxDrawable */
  METHOD hitCheck(insideX, insideY) RETURNS hit:BOOL
  METHOD overlaps(drawable:PTR TO cGfxDrawable, insideX, insideY) RETURNS overlaps:BOOL

hitCheck() returns whether a particular point (relative to the top left of the drawable) will be drawn or not. (This is used by cGfxStack's findSpriteAt() method.)

overlaps() returns whether the provided drawable would overlap the current drawable, if the provided one was offset from the current one by the given coordinates (which are relative to the top left of the current drawable). If either drawable is a bitmap with a mask, then that will be taken into account. This method is handy for performing collision detection.

The following methods are for EXPERT users only:

  /* more methods of cGfxDrawable */
  METHOD changeUseCount(increaseBy)
  METHOD infoUseCount() RETURNS useCount
  METHOD changeVisibleCount(increaseBy)
  METHOD infoVisibleCount() RETURNS visibleCount
  METHOD registerForChanges(  client:PTR TO cGfxNotifyOfDrawableChanges)
  METHOD unregisterForChanges(client:PTR TO cGfxNotifyOfDrawableChanges)
  METHOD addToGfx(gfx:PTR TO cGfxWindow)

changeUseCount() & infoUseCount() is used to change & retrieve how many times this object is used by things like sprites. The use count is reduced by using negative values for increaseBy. And useCount defaults to 0. You do not normally need to use these methods! (This is used by the cGfxSprite class to prevent it's drawable frames from being destroyed when it is still using them.)

changeVisibleCount() & infoVisibleCount() is used to change & retrieve how many times this object is visible within the current window. The visibile count is reduced by using negative values for increaseBy. And visibleCount defaults to 0. You do not normally need to use these methods! (This is used by the cGfxBitmap sub-class to make itself non-drawable when it's visible count drops to 0, to save video memory. The cGfxSprite class uses it.)

registerForChanges() & unregisterForChanges() are used to tell this drawable when another object needs to know that it's size or contents changes. You do not normally need to use these methods! (This is used by the cGfxSprite class to redraw itself when it's drawable is changed.)

Note that any sub-class of cGfxNotifyOfDrawableChanges should implement this method:

  drawableHasChanged(oldWidth, oldHeight, drawable:PTR TO cGfxDrawable)

addToGfx() should only be called once, by the drawable itself. This registers it with the cGfxWindow that it draws to, so that it will be automatically destroyed when the cGfxWindow is destroyed. gfx is stored in the inherited member self.gfx, which you can read yourself if needed. You never need to use this method, unless you are creating your own cGfxDrawable sub-class.

21.5. Methods of cGfxBitmap

The cGfxBitmap class is a special kind of cGfxDrawable class, which is a bitmap (picture) that can be drawn into the window. Bitmaps use video memory, unless they are made non-drawable (in which case the draw() method will throw an exception if you try to use it).

  /* Methods of cGfxBitmap, which inherits cGfxDrawable */
  METHOD clone(changeIsDrawable=FALSE:BOOL, isDrawable=FALSE:BOOL) RETURNS clone:PTR TO cGfxBitmap
  METHOD extract(x, y, width, height, changeIsDrawable=FALSE:BOOL, isDrawable=FALSE:BOOL) RETURNS copy:PTR TO cGfxBitmap
  METHOD setIsDrawable(isDrawable:BOOL)
  METHOD getIsDrawable() RETURNS isDrawable:BOOL

clone() creates & returns a copy of the bitmap. If you want to change the drawable state then give TRUE for changeIsDrawable, in which case isDrawable will indicate whether the new bitmap should be drawable or not.

extract() creates & returns a copy of part of the bitmap. x,y gives the top left corner of the new bitmap (where 0,0 is the existing corner), and width,height gives the size of the new bitmap. If you try to copy beyond the edge of the bitmap then an exception will be thrown. As with the clone() method, you can change the drawable state of the new bitmap.

setIsDrawable() & getIsDrawable() allow you to change & retrieve the drawable state. When a bitmap is drawable it uses video memory, and you are allowed to use the draw() method.

  /* more methods of cGfxBitmap */
  METHOD savePicture(file:ARRAY OF CHAR, ignoreMask=FALSE:BOOL) RETURNS success:BOOL
  METHOD flip(horizontally:BOOL, vertically:BOOL)
  METHOD rotate(degrees)
  METHOD scaleTo(newWidth, newHeight)
  METHOD scaleBy(multiplier, divider)
  METHOD makeScaledTo(newWidth, newHeight) RETURNS scaledBitmap:PTR TO cGfxBitmap
  METHOD makeScaledBy(multiplier, divider) RETURNS scaledBitmap:PTR TO cGfxBitmap
  ->plus methods inherited from cGfxDrawable

For the inherited methods read 21.4. Methods of cGfxDrawable.

savePicture() saves the current bitmap as a picture, in a standard format (IFF on Amiga, although it will be PNG on AROS). Normally the mask will be saved as part of the picture, but you can use TRUE for ignoreMask to prevent this. It returns whether saving the picture was successful or not.

flip() horizontally and/or vertically flips the bitmap, such that it becomes the mirror-image of itself.

rotate() rotates the bitmap clockwise. degrees must be in 90 degree steps, such that 0, 90, 180 and 270 are allowed.

scaleTo() enlarges or shrinks the bitmap to the given size.

scaleBy() enlarges or shrinks the bitmap by the ratio multiplier / divider. Thus it enlarges it by the integer multiplier, and shrinks it by the integer divider. Both width & height are scaled by the same amount.

makeScaledTo() & makeScaledBy() are the same as the scaleTo() & scaleBy() methods, except that they return a new (scaled) bitmap, rather than modify the existing one. (This is more efficient than clone()ing a bitmap & then using scaleTo() or scaleBy().)

21.6. Events

All events are described by up to four returned values:

  type, subType, value, value2

Where type can be one of the following values:

  EVENT_NONE, EVENT_MOUSE, EVENT_KEY, EVENT_WINDOW, EVENT_TIMER, EVENT_UNKNOWN

Where subType gives more information on the kind of event:

  EVENT_MOUSE_MOVE, EVENT_MOUSE_SCROLL, EVENT_MOUSE_DOUBLECLICK, EVENT_MOUSE_LEFT, EVENT_MOUSE_LEFTUP, EVENT_MOUSE_RIGHT, EVENT_MOUSE_RIGHTUP, EVENT_MOUSE_MIDDLE, EVENT_MOUSE_MIDDLEUP
  EVENT_KEY_ASCII, EVENT_KEY_ASCIIUP, EVENT_KEY_SPECIAL, EVENT_KEY_SPECIALUP
  EVENT_WINDOW_CLOSE, EVENT_WINDOW_ACTIVE, EVENT_WINDOW_INACTIVE, EVENT_WINDOW_RESIZED
  EVENT_TIMER_EXPIRED
  EVENT_UNKNOWN_DONOTUSE
  ->EVENT_SCREEN_REFRESH

Where value and value2 are optional, and their meaning depends on the event subType.


Beware that different event types can use the same subType values, so you MUST check type before you check subType. When type is EVENT_x, you need to check for subTypes that begin with EVENT_x_. For example, when type is EVENT_KEY, you must check for the subTypes EVENT_KEY_ASCII & EVENT_KEY_SPECIAL.


Here is a description of subTypes, and what value & value2 mean (if anything):

  EVENT_MOUSE_MOVE   indicates that the mouse has been moved to x,y location value,value2.
  EVENT_MOUSE_SCROLL indicates that the scroll wheel has been moved by value,value2 for x,y steps.
  EVENT_MOUSE_DOUBLECLICK indicates the left   mouse button has been double-clicked at x,y location value,value2.
  EVENT_MOUSE_LEFT        indicates the left   mouse button has been depressed at x,y location value,value2.
  EVENT_MOUSE_RIGHT       indicates the right  mouse button has been depressed at x,y location value,value2.
  EVENT_MOUSE_MIDDLE      indicates the middle mouse button has been depressed at x,y location value,value2.
  EVENT_MOUSE_LEFTUP      indicates the left   mouse button has been raised at x,y location value,value2.
  EVENT_MOUSE_RIGHTUP     indicates the right  mouse button has been raised at x,y location value,value2.
  EVENT_MOUSE_MIDDLEUP    indicates the middle mouse button has been raised at x,y location value,value2.
  
  EVENT_KEY_ASCII     indicates that a  normal key has been pressed,  with "value" for the ascii code.
  EVENT_KEY_SPECIAL   indicates that a special key has been pressed,  with "value" being a constant (see later).
  EVENT_KEY_ASCIIUP   indicates that a  normal key has been released (with "value" for the ascii code).
  EVENT_KEY_SPECIALUP indicates that a special key has been released (with "value" being a constant).
  
  EVENT_WINDOW_CLOSE    indicates that the user has asked the window to close.
  EVENT_WINDOW_ACTIVE   indicates that the window became active (e.g. the user clicked on it).
  EVENT_WINDOW_INACTIVE indicates that the window became inactive (e.g. the user clicked on another window).
  EVENT_WINDOW_RESIZED  indicates that the window has changed size (with value,value2 being the new width,height).
  
  EVENT_TIMER_EXPIRED indicates that a cGfx timer has completed the given time.
  
  EVENT_UNKNOWN_DONOTUSE should not be used!
  
  EVENT_SCREEN_REFRESH indicates a screen refresh has occured. It is not guaranteed to be available, and may even be removed in the future!

When subType is EVENT_KEY_SPECIAL, value can be one of these self-explanatory constants:

  EVENT_KEY_SPECIAL_ENTER, EVENT_KEY_SPECIAL_ESCAPE, EVENT_KEY_SPECIAL_TAB, EVENT_KEY_SPECIAL_BACKSPACE,
  EVENT_KEY_SPECIAL_INSERT, EVENT_KEY_SPECIAL_DELETE, EVENT_KEY_SPECIAL_HOME, EVENT_KEY_SPECIAL_END, EVENT_KEY_SPECIAL_PAGEUP, EVENT_KEY_SPECIAL_PAGEDOWN,
  EVENT_KEY_SPECIAL_UP, EVENT_KEY_SPECIAL_DOWN, EVENT_KEY_SPECIAL_LEFT, EVENT_KEY_SPECIAL_RIGHT, EVENT_KEY_SPECIAL_LSHIFT, EVENT_KEY_SPECIAL_RSHIFT, EVENT_KEY_SPECIAL_LCTRL, EVENT_KEY_SPECIAL_RCTRL, EVENT_KEY_SPECIAL_LALT, EVENT_KEY_SPECIAL_RALT, EVENT_KEY_SPECIAL_LCOMMAND, EVENT_KEY_SPECIAL_RCOMMAND,
  EVENT_KEY_SPECIAL_F1, EVENT_KEY_SPECIAL_F2, EVENT_KEY_SPECIAL_F3, EVENT_KEY_SPECIAL_F4, EVENT_KEY_SPECIAL_F5, EVENT_KEY_SPECIAL_F6, EVENT_KEY_SPECIAL_F7, EVENT_KEY_SPECIAL_F8, EVENT_KEY_SPECIAL_F9, EVENT_KEY_SPECIAL_F10

21.7. Creating your own cGfxDrawable sub-class

What does a sub-class of cGfxDrawable actually do? It is an object which behaves very much like a cGfxBitmap, and so you can (for example) ask it to draw itself at a particular location, using it's draw(x,y) method.

Why would you want to do that? On it's own this isn't much use, but if you write some code that draws a user-supplied bitmap somewhere, then it might be handy if it could also draw other things. One obvious example is the 'std/cGfxSprites' module, which allows you to have sprites. In that case you can have sprites draw something other than a simple bitmap (e.g. some text that changes). A specific example can be found here:

  Examples/std/Graphics/StarsXY_ToySpaceshipSprite1.e

This example has an animated "3D star field" as a drawable object, and uses this as the background upon which a spaceship sprite moves around.


So how do you go about creating a cGfxDrawable sub-class? The previously mentioned example gives a nice concrete demonstration of how to do it, but you might like to know the theory behind it...

First you should take a look at the 21.4. Methods of cGfxDrawable sub-chapter, to see what methods your object will have. Back again? There were rather a lot of methods, right? Don't worry about that! Many of them have sensible defaults, so you can probably get away with writing only the following methods:

  METHOD infoWidth()  RETURNS width
  METHOD infoHeight() RETURNS height
  METHOD draw(x, y)

They should be pretty self-explanatory. infoWidth() & infoHeight() simply report the actual size of your object. It is VERY important that your object has a fixed size. draw() simply uses the standard cGfx methods to draw your object at the given coordinates. It is VERY important that your object draws the same thing each time this method is called.

But what if you want to change the size of your object, or change what it draws? You can do that, but it should only happen when a method of your object is called. You will have to invent your own method! In the case of the previously mentioned example, the method is named setStarsOrigin() since it moves your viewpoint of the stars. In any case, it is VERY important that this method finishes with the following bit of code:

  self.notifyClientsOfChange(oldWidth, oldHeight)

Where oldWidth & oldHeight give the OLD size of your object. You MUST do this even if your object's size has not changed, so that anything using your object will know that it's contents has changed, and thus redraw it if necessary.

But how does your object know it's size & target window in the first place? This is where your object's constructor comes in. While you can call this method anything you want, it is usual to call it new(). Thus you MIGHT have a constructor method that looks like this:

  PROC new(win:PTR TO cGfxWindow, width, height) OF myDrawable
  	self.addToGfx(win)
  	self.width  := width
  	self.height := height
  ENDPROC

Note that your constructor MUST call the addToGfx() method. And you don't need to store win yourself, because it will do that for you in the inherited member self.gfx .

And then your object would look like this:

  CLASS myDrawable OF cGfxDrawable
  	width
  	height
  ENDCLASS

And your "info" methods would look like this:

  PROC infoWidth()  OF myDrawable RETURNS width  IS self.width
  
  PROC infoHeight() OF myDrawable RETURNS height IS self.height
  
Of course your ||draw()|| method depends on exactly what your object draws!  But
it might look like this:
  PROC draw(x, y) OF myDrawable
    self.gfx.setColour($FF0000)
    self.gfx.drawBox(x, y, self.width, self.height)
  ENDPROC

You would create your object using code along these lines:

  DEF foo:PTR TO myDrawable
  
  NEW foo.new(gfx, 100, 100)

If you are creating a drawable for use as a background for sprites (as in the previously mentioned example), then you should be aware of an extra limitation. Usually your drawable will be tiled, which means it must look ok when it is tiled. This is usually easy to manage for 2D effects, but if it contains a fake 3D perspective then you cannot normally do it. It just so happens that the fake 3D parallax algorithm used by the StarsXY_ToySpaceshipSprite1.e example can be tiled, but that is a very unusual case.


What about those other cGfxDrawable methods that we ignored? If your object is transparent (i.e. it does NOT draw every pixel within it's given size) then you will need to consider writing the following methods:

  METHOD infoIsTransparent() RETURNS isTransparent:BOOL
  METHOD hitCheck(insideX, insideY) RETURNS hit:BOOL
  METHOD overlaps(drawable:PTR TO cGfxDrawable, insideX, insideY) RETURNS overlaps:BOOL

infoIsTransparent() must return TRUE. You can ignore the other two methods, unless you want to perform accurate collision-detection on your drawable object. hitCheck() shouldn't be too hard to write, but overlaps() may be impossible! Probably the best you can do for overlaps() is to check whether drawable is one of your own objects (using the IsOfClassType() method), and only in that case will you have enough information that you can perform a more accurate overlap check (in all other cases you will need to fall-back on the default parent method, by calling SUPER self.overlaps(drawable, insideX, insideY)).


But what about those other methods we ignored? If your object contains other drawables (typically bitmaps), then you will need to write the following methods:

  METHOD changeVisibleCount(increaseBy)
  METHOD registerForChanges(  client:PTR TO cGfxNotifyOfDrawableChanges)
  METHOD unregisterForChanges(client:PTR TO cGfxNotifyOfDrawableChanges)

For each of these methods, you must call the same method on all the drawables you contain, and then call the parent method. For example, say that your drawable object contains the member picture:PTR TO cGfxBitmap, then your methods would look like this:

  PROC changeVisibleCount(increaseBy) OF myDrawable
  	self.picture.changeVisibleCount(increaseBy)
  	
  	SUPER self.changeVisibleCount(increaseBy)
  ENDPROC
  
  PROC registerForChanges(client:PTR TO cGfxNotifyOfDrawableChanges) OF myDrawable
  	self.picture.registerForChanges(client)
  	
  	SUPER self.registerForChanges(client)
  ENDPROC
  
  PROC unregisterForChanges(client:PTR TO cGfxNotifyOfDrawableChanges) OF myDrawable
  	self.picture.unregisterForChanges(client)
  	
  	SUPER self.unregisterForChanges(client)
  ENDPROC

That should cover everything you need to know, but as this is quite an advanced subject, feel free to ask me about anything that is not clear. And of course remember to look at the StarsXY_ToySpaceshipSprite1.e example.

Go back to CONTENTS


22. MODULE 'std/cGfxSpritesSimple'

This module is the same as the cGfxSprites module (which provides sprite-based graphics), except that it provides a few extras to simplify things for beginners. Those extras are detailed below.

Beware that you canNOT use this module at the same time as the cGfxSimple module, to draw within the same window. Use one or the other, but not both at the same time.

Supported OSes: The same as cGfx.

22.1. Example usage

When you use this module, it automatically uses the window you open:

  IsDesktopApp()	->you only need to do this once!
  OpenWindow(640, 480)

Here's one way to create & move a sprite.

  StoreBitmap('player', 0, LoadPicture('spaceship.gif'))
  StoreSprite('player', 0, CreateSprite(20,20, LastBitmap()))
  
  Pause(20)                             ->wait 2 seconds
  UseSprite('player', 0).move(30,0)     ->move the sprite horizontally
  LastSprite().move(50,0)               ->move the sprite again

Here's another way to create & move a sprite:

  DEF playerSprite:PTR TO cGfxSprite, playerBitmap:PTR TO cGfxBitmap
  
  playerBitmap := LoadPicture('spaceship.gif')
  playerSprite := CreateSprite(20,20, playerBitmap)
  
  Pause(20)                  ->wait 2 seconds
  playerSprite.move(30,0)    ->move the sprite horizontally
  playerSprite.move(50,0)    ->move the sprite again

Here's how to move a sprite smoothly:

  SetAutoUpdate(FALSE)
  REPEAT
     playerSprite.move(1,0)
     UpdateAndWaitForScreenRefresh()
  UNTIL playerSprite.getPosition() >= InfoWidth()

The following example programs use it:

  Examples/std/Graphics/StarsXY_ToySpaceshipSprite1.e
  Examples/std/Graphics/StarsZYX_ToySpaceshipSprite1.e
  Examples/std/Graphics/ToySpaceshipSprite1.e
  Examples/std/Graphics/ToySpaceshipSprite2.e
  Examples/std/Multimedia/ShadowOfTheBlitz_Scroller/SOTB.e

Released programs which are known to use it:

  Ami-Ingenious    ( os4depot.net/?function=showfile&file=game/board/ami-ingenious.lha )
  Davideope puzzle ( os4depot.net/?function=showfile&file=game/puzzle/davidope_puzzle.lha )
  FlowerWay        ( os4depot.net/?function=showfile&file=game/puzzle/flowerway.lha )
  7-boings         ( os4depot.net/?function=showfile&file=game/puzzle/7boings.lha )
  Age of Thieves   ( os4depot.net/?function=showfile&file=game/board/age_of_thieves.lha )

22.2. Details

You do not need to use CreateGfxStack(), because it is automatically called, with the result stored in the gfxStack global variable. And the first layer is automatically stored in the gfxLayer global variable.

Note that you don't need to call CreateGfxWindow() either, because the cGfxSimple module is used.

22.3. Procedures

  PROC LastSprite() RETURNS sprite:PTR TO cGfxSprite

LastSprite() gives you the last sprite that was returned by one of the following procedures. If there was no last sprite, then it protects you by throwing an exception.

  PROC DestroySprite(sprite:PTR TO cGfxSprite) RETURNS nil:PTR TO cGfxSprite
  PROC FindSpriteAt(x, y, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite
  PROC FindSpriteOverlapping(sprite:PTR TO cGfxSprite, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite
  PROC StoreSprite(name:ARRAY OF CHAR, number, sprite:PTR TO cGfxSprite) RETURNS storedSprite:PTR TO cGfxSprite
  PROC UseSprite(  name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS sprite:PTR TO cGfxSprite
  PROC SetBackgroundColour(rgb)
  PROC SetBackgroundDrawable(drawable=NIL:PTR TO cGfxDrawable, x=0, y=0, noTileX=FALSE:BOOL, noTileY=FALSE:BOOL, noScrollX=FALSE:BOOL, noScrollY=FALSE:BOOL)
  PROC ScrollAllSprites(dx, dy)
  PROC ScrollAllLayers(dx, dy)

These are the same as cGfxStack's methods (see chapter 23.3. Methods of cGfxStack), but they look simpler because they are procedures. Only the most important methods are available as procedures, and unlike the methods they start with a capital letter.

(Note that cGfxSimple's UpdateAndWaitForScreenRefresh() procedure is modified to automatically call cGfxStack's redraw() method, so you don't need to. And cGfxSimple's SetAutoUpdate() procedure is modified to automatically call cGfxStack's setAutoRedraw() method, so you don't need to. The upshot of this is that the sprite system will work much more efficiently when you use SetAutoUpdate(FALSE).)

  PROC ScrollSprites(dx, dy)
  PROC ScrollLayer(dx, dy)
  PROC SetOrigin(x, y)
  PROC GetOrigin() RETURNS x, y
  PROC CreateSprite(x, y, drawable:PTR TO cGfxDrawable, hidden=FALSE:BOOL) RETURNS sprite:PTR TO cGfxSprite

These are the same as cGfxLayer's methods (see chapter 23.4. Methods of cGfxLayer), but they look simpler because they are procedures. They always operate on gfxLayer, which is the top layer of sprites. Only the most important methods are available as procedures, and unlike the methods they start with a capital letter.

  PROC FullyRedrawSprites()

FullyRedrawSprites() will force all the sprites to be redrawn. This is useful if you want to "clean up" after have directly drawn in the window using 'std/cGfx'.


Go back to CONTENTS


23. MODULE 'std/cGfxSprites'

This module provides fairly easy sprite-based graphics (and was written using the cGfx module itself).

While there are some advanced features, the default behaviour is quite simple: A cGfxStack covers the entire window, and is given the responsibility for all drawing in that window. It is a stack of cGfxLayers (you start with just one). Each cGfxLayer is a layer of cGfxSprites. And each cGfxSprite is just a bitmap that knows what position it should be drawn at.

A cGfxStack initially has one layer, and you can create sprites in that layer. You can change the position of sprites at any time, and see the result immediately.

You can get away with just using a single layer, but they are very handy for organising your sprites. For example:

Supported OSes: The same as cGfx.

23.1. Example usage

The simplest way to create a stack:

  DEF win:PTR TO cGfxWindow, stack:PTR TO cGfxStack
  
  CreateApp().build()
  win := CreateGfxWindow('demo')
  win.openWindow(640, 480)
  stack := CreateGfxStack(win)

How to create & move a sprite:

  DEF layer:PTR TO cGfxLayer, sprite:PTR TO cGfxSprite
  
  layer  := stack.infoTopLayer()
  sprite := layer.createSprite(20,20, win.loadPicture('SomePicture.jpg'))
  
  Pause(20)            ->wait 2 seconds
  sprite.move(30,0)    ->move the sprite horizontally

The following example programs use it:

  Examples/std/Multimedia/ShootEmUp/ShootEmUp.e

Released programs which are known to use it:

  PictureAlbum ( cshandley.co.uk )

23.2. Procedures

  PROC  CreateGfxStack(gfx:PTR TO cGfxWindow)  RETURNS stack:PTR TO cGfxStack
  PROC DestroyGfxStack(stack:PTR TO cGfxStack) RETURNS nil:PTR TO cGfxStack

CreateGfxStack() creates & returns a cGfxStack object using the supplied window. By default it covers the whole window, so you must use the setRegion() method if you want to change that.

DestroyGfxStack() destroys the supplied stack. It will also destroy all layers & sprites inside the stack. The stacks will be automatically destroyed when your program quits, so you may not need to use this! You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

23.3. Methods of cGfxStack

A single cGfxStack normally covers the entire window, but it can be restricted to a region. It is given the responsibility for all drawing (and refreshing) of it's region, so you must never (use a cGfxWindow or cGfxBitmap to) draw there yourself! A cGfxStack is a stack of cGfxLayers, with each layer on top of the next one.

  /* Methods of cGfxStack */
  METHOD infoTopLayer()    RETURNS    top:PTR TO cGfxLayer
  METHOD infoBottomLayer() RETURNS bottom:PTR TO cGfxLayer
  METHOD destroyLayer(layer:PTR TO cGfxLayer) RETURNS nil:PTR TO cGfxLayer
  METHOD destroySprite(sprite:PTR TO cGfxSprite) RETURNS nil:PTR TO cGfxSprite
  METHOD findSpriteAt(x, y, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite
  METHOD findSpriteOverlapping(sprite:PTR TO cGfxSprite, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite
  METHOD storeSprite(name:ARRAY OF CHAR, number, sprite:PTR TO cGfxSprite) RETURNS storedSprite:PTR TO cGfxSprite
  METHOD useSprite(  name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS sprite:PTR TO cGfxSprite

infoTopLayer() returns the layer at the top of the stack, whose sprites appear above all the other layers.

infoBottomLayer() returns the layer at the bottom of the stack, which is a special layer that is a solid (background) colour. You should not try to add sprites to this layer, nor destroy it.

destroyLayer() destroys the supplied layer, along with all it's sprites. You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

destroySprite() destroys the supplied sprite. The sprite's bitmap/drawable will not be destroyed. You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

findSpriteAt() searches all the layers (from the top downwards), looking for a sprite at the given position. It returns the first sprite that it finds. If you want to continue looking, then for lastMatch you must give the previously returned sprite.

findSpriteOverlapping() searches all the layers (from the top downwards), looking for a sprite which overlaps the given sprite. It returns the first sprite that it finds. If you want to continue looking, then for lastMatch you must give the previously returned sprite.

storeSprite() & useSprite() allow you to store & retrieve sprites using a name string, and optionally a number. The string must be an 'immediate string', not one you have created. It returns the stored sprite, so you can use it straight away. Here's an example of how you might use it:

  stack.storeSprite('player', 0, layer.createSprite(x,y, playerBitmap, TRUE))
  
  stack.useSprite('player', 0).setHidden(FALSE)

If you try to store more than one sprite with the same name & number combination, then an exception will be raised. This is to prevent you accidentally reusing them. And if you try to use a non-existant sprite, then an exception will be raised; unless you gave TRUE for allowReturnNIL, in which case NIL will be returned.

  /* more methods of cGfxStack */
  METHOD setBackgroundColour(rgb)
  METHOD getBackgroundColour() RETURNS rgb
  METHOD setBackgroundDrawable(drawable=NIL:PTR TO cGfxDrawable, x=0, y=0, noTileX=FALSE:BOOL, noTileY=FALSE:BOOL, noScrollX=FALSE:BOOL, noScrollY=FALSE:BOOL)
  METHOD getBackgroundDrawable() RETURNS drawable:PTR TO cGfxDrawable
  METHOD setRegion(x=0, y=0, width=-1, height=-1)
  METHOD getRegion() RETURNS x, y, width, height
  METHOD scrollAllSprites(dx, dy)
  METHOD scrollAllLayers(dx, dy)

setBackgroundColour() & getBackgroundColour() allow you to change & retrieve the colour of the special background layer.

setBackgroundDrawable() & getBackgroundDrawable() allow you to change & retrieve a drawable/bitmap for the special background layer. The drawable/bitmap will be tiled, unless you use noTileX & noTileY. The drawable/bitmap will be scrolled by the scrollAllSprites() & scrollAllLayers() methods, unless you use noScrollX & noScrollY, in which case scrolling canNOT be optimised. Note that if the bitmap has a mask then the background colour will show through.

setRegion() & getRegion() allow you to change & retrieve the rectangular region which the stack is responsible for drawing. If you set width/height to -1 then the right/bottom of the region is set to the edge of the window.

scrollAllSprites() causes all sprites to be to be moved by the same dx,dy pixels. It does this by changing the sprite positions. This is done very efficiently, without having to redraw most of the stack... UNLESS the background drawable is prevent from being scrolled (by noScrollX/Y). Or unless the scrolling is done in both X & Y directions.

You would tend to use this for game worlds where sprites only exist to be seen by the player (so you will want sprite positions to correspond to their on-screen position). For example Shoot-em'ups.

scrollAllLayers() causes all layers to be moved by dx,dy pixels (the sprites move along with their layer). It does this by changing the layer "origin". This is done very efficiently, without having to redraw most of the stack... UNLESS the background drawable is prevent from being scrolled (by noScrollX/Y)... Or unless the scrolling is done in both X & Y directions.

You would tend to use this for game worlds where sprites exist even when they cannot be seen by the player (so you will want the sprite positions to correspond to their position in the simulated game world). For example Real Time Strategy & RPG games.

  /* more methods of cGfxStack */
  METHOD setAutoRedraw(autoRedraw:BOOL)
  METHOD getAutoRedraw() RETURNS autoRedraw:BOOL
  METHOD redraw(forceFull=FALSE:BOOL)

setAutoRedraw() allows you to change whether the stack should automatically redraw itself after every change. It defaults to automatic redrawing, which is easier, but far less efficient.

If you disable autoRedraw then you must call the redraw() method when you have finished updating the stack. You would be advised to also disable cGfx's autoUpdate, and then call redraw() shortly before calling it's updateAndWaitForScreenRefresh() method. Note that the procedures of the 'std/cGfxSpriteSimple' module automatically call redraw(), so you don't have to.

getAutoRedraw() returns whether the stack is automatically redrawing or not.

redraw() forces the stack to redraw anything that you have changed since the last redraw(). If you give TRUE for forceFull then the entire stack will be redrawn, even where no sprites have changed. forceFull is useful if you want to "clean up" after have directly drawn inside the stack's area.

  /* more methods of cGfxStack */
  METHOD setAutoIsDrawable(autoIsDrawable:BOOL)
  METHOD getAutoIsDrawable() RETURNS autoIsDrawable:BOOL

setAutoIsDrawable() allows you to call cGfxLayer's setAutoIsDrawable() method on all the layers.

getAutoIsDrawable() returns the last value that the setAutoIsDrawable() method was called with. It is used by all layers that are created. By default autoIsDrawable is TRUE

23.4. Methods of cGfxLayer

Each cGfxLayer is a layer of cGfxSprites. Sprites in the layer above will always appear above the sprites in the layer below. Within a layer the sprites should not normally overlap, but if they do then those sprites will appear above or below each other according to their order in the layer (which you can change).

Sprite positions are relative to the "origin" of it's layer (which is normally the top left of the window). This can be used to make all the layer's sprites scroll in a direction.

  /* Methods of cGfxLayer */
  METHOD scrollSprites(dx, dy)
  METHOD scrollLayer(dx, dy)
  METHOD setOrigin(x, y)
  METHOD getOrigin() RETURNS x, y

scrollSprites() causes all sprites (on the layer) to be moved by dx,dy pixels. It does this by changing the sprite positions.

You would tend to use this for game worlds where sprites only exist to be seen by the player (so you will want sprite positions to correspond to their on-screen position). For example Shoot-em'ups.

scrollLayer() causes the layer to be moved by dx,dy pixels (the sprites will move along with the layer). It does this by changing the layer's "origin".

You would tend to use this for game worlds where sprites exist even when they cannot be seen by the player (so you will want the sprite positions to correspond to their position in the simulated game world). For example Real Time Strategy & RPG games.

setOrigin() & getOrigin() allow you to change & retrieve the "origin" of the layer, which will result in all the sprites moving.

  /* more methods of cGfxLayer */
  METHOD createSprite(x, y, drawable:PTR TO cGfxDrawable, hidden=FALSE:BOOL) RETURNS sprite:PTR TO cGfxSprite
  METHOD findSpriteAt(x, y, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite
  METHOD findSpriteOverlapping(sprite:PTR TO cGfxSprite, lastMatch=NIL:PTR TO cGfxSprite) RETURNS match:PTR TO cGfxSprite

createSprite() creates & returns a sprite at position x,y in the layer. You would usually give a bitmap for drawable, but other drawables (such as returned by the cGfx.makeText() method) are also fine. The sprite is created at the 'top' of the layer. If you give TRUE for hidden then the sprite won't be visible.

You can use the same bitmap/drawable for many sprites, allowing you to save video memory. But this also means you must NOT destroy the bitmap/drawable while you are using the sprite!

findSpriteAt() does the same as cGfxStack's findSpriteAt() method, except that it only searches this layer.

findSpriteOverlapping() does the same as cGfxStack's findSpriteOverlapping() method, except that it only searches this layer.

  /* more methods of cGfxLayer */
  METHOD createLayerBelow() RETURNS layer:PTR TO cGfxLayer
  METHOD infoAbove() RETURNS above:PTR TO cGfxLayer
  METHOD infoBelow() RETURNS below:PTR TO cGfxLayer
  METHOD infoHasSprites()   RETURNS hasSprites:BOOL
  METHOD infoTopSprite()    RETURNS sprite:PTR TO cGfxSprite
  METHOD infoBottomSprite() RETURNS sprite:PTR TO cGfxSprite

createLayerBelow() creates & returns a layer below the current one.

infoAbove() returns the layer above the current one, however if you are already on the top layer, then the bottom layer will be returned!

infoBelow() returns the layer below the current one, however if you are already on the bottom layer, then the top layer will be returned!

infoHasSprites() returns whether or not the layer contains any sprites.

infoTopSprite() returns the sprite at the top of the layer, which appears above all other sprites in that layer. If there are no sprites then an exception will be raised, so you should first check using infoHasSprites().

infoBottomSprite() returns the sprite at the bottom of the layer.

  /* more methods of cGfxLayer */
  METHOD setAutoIsDrawable(autoIsDrawable:BOOL)
  METHOD getAutoIsDrawable() RETURNS autoIsDrawable:BOOL

setAutoIsDrawable() allows you to change whether the sprites in this layer have their bitmaps/etc automatically made drawable or not (using cGfxBitmap's setIsDrawable() method) according to whether they are visible in the stack's region or not. Thus if a bitmap is not being used by any sprite that can be seen, then it will be made non-drawable, and so save your precious video memory! The downside to this is that it takes a short while to load the bitmap back into memory (when it becomes visible again), but you should not notice this unless many (or huge) bitmaps have to be loaded back at the same time.

The stack defaults to creating all layers with TRUE for autoIsDrawable.

getAutoIsDrawable() returns whether the sprites in this layer have their bitmaps/drawables automatically made drawable or not.

23.5. Methods of cGfxSprite

Each cGfxSprite is a bitmap that will be drawn at a given position. The position of sprites are unaffected by where cGfxStack's region is, and so are normally given using their actual position in the window. However, if the "origin" of the layer is moved away from the top left corner of the window, then the visible position of all sprites will be moved along with it.

  /* Methods of cGfxSprite */
  METHOD infoWidth()  RETURNS width
  METHOD infoHeight() RETURNS height
  METHOD infoLayer()  RETURNS layer:PTR TO cGfxLayer
  METHOD infoAbove() RETURNS sprite:PTR TO cGfxSprite
  METHOD infoBelow() RETURNS sprite:PTR TO cGfxSprite
  METHOD infoIsInsideRegion(fullyInside=FALSE:BOOL) RETURNS insideRegion:BOOL

infoWidth() & infoHeight() return the size of the sprite.

infoLayer() returns the layer the sprite is in.

infoAbove() returns the sprite above the current one, however if you are already on the top sprite, then the bottom sprite will be returned!

infoBelow() returns the sprite below the current one, however if you are already on the bottom sprite, then the top sprite will be returned!

infoIsInsideRegion() returns whether the sprite is inside the stack's region (and thus potentially visible). By default fullyInside is FALSE, which means it returns TRUE even if the sprite is only partially inside the region. If you give TRUE for fullyInside then it only returns TRUE if the sprite is completely inside the region.

  /* more methods of cGfxSprite */
  METHOD move(dx, dy)
  METHOD setPosition(x, y)
  METHOD getPosition() RETURNS x, y
  METHOD setHidden(hidden:BOOL)
  METHOD getHidden()
  METHOD setDrawable(drawable:PTR TO cGfxDrawable, frame=0)
  METHOD getDrawable(frame=0) RETURNS drawable:PTR TO cGfxDrawable
  METHOD setFrame(frame) RETURNS exists:BOOL
  METHOD getFrame() RETURNS frame
  METHOD setTiled(tileX:BOOL, tileY:BOOL)
  METHOD getTiled() RETURNS tileX:BOOL, tileY:BOOL
  METHOD setData(data)
  METHOD getData() RETURNS data
  METHOD setDataBox(data:OWNS PTR TO class)
  METHOD getDataBox() RETURNS data:PTR TO class

move() allows you to change the sprite's position by dx,dy pixels.

setPosition() & getPosition() allow you to change & retrieve the position of the sprite within the layer. The position is relative to the layer's "origin".

setHidden() & getHidden() allow you to change & retrieve whether the sprite is invisible or not.

setDrawable() & getDrawable() allow you to change & retrieve the bitmap/drawable used by the sprite. If you supply a frame number, then you will store & retrieve the bitmap/drawable of the given animation frame.

Rather than just changing frame 0 to change the sprite's appearance, you should let the sprite know all the frames it will be showing, and then using setFrame() to change the shown frame. Not only is this easier to manage sprite animation, but the sprite will ensure that all frames are drawable (when autoIsDrawable is enabled) so that your animations are smooth.

setFrame() & getFrame() allow you to change & retrieve the currently shown frame number. setFrame() will return TRUE for exists when the given frame existed.

setTiled() & getTiled() allow you to change & retrieve whether the sprite is tiled across the whole window or not. Normal sprites are NOT tiled, but if you make them tiled then they appear to be infinitely wide (when tileX is TRUE) and/or infinitely tall (when tileY is TRUE). When tiled, their drawable will be repeated in a 'tiled' fashion, thus allowing you to easily have background(s) that go on 'forever'.

Note that tiled sprites can still be moved by changing their position. And you can still perform collision (hit/overlap) checks with tiled sprites.

setData() & getData() allow you to store & retrieve one piece of data for each sprite. If you need to store a PTR, ARRAY, STRING or LIST, then please use setDataBox() & getDataBox() instead.

setDataBox() & getDataBox() allow you to store & retrieve one box (containing a piece of data) for each sprite. This box typically contains some data related to the sprite. Note that the box is automatically deallocated.

Although you can store any class object, it is expected that typically you will store a "box", and thus will use the 'std/pBox' module. Here is a typical usage example:

  mySprite.setDataBox(BoxARRAY('a string is an array!'))
  Print('The sprite contains "\s"\n', UnboxARRAY(mySprite.getDataBox()))

Here is a slightly more complex example:

  mySprite.setDataBox(BoxSTRING(NEW 'this is turned into an e-STRING by NEW'))
  Print('The sprite contains "\s"\n', UnboxSTRING(mySprite.getDataBox()))
  /* more methods of cGfxSprite */
  METHOD overlaps(sprite:PTR TO cGfxSprite) RETURNS overlaps:BOOL
  METHOD moveToBottomOfLayer()
  METHOD moveToTopOfLayer()
  METHOD clone() RETURNS clone:PTR TO cGfxSprite

overlaps() returns whether the given sprite overlaps the current sprite. Bitmap masks are taken into account.

moveToBottomOfLayer() allows you to move the sprite to the 'bottom' of the layer, so all other sprites in the layer will appear above it.

moveToTopOfLayer() allows you to move the sprite to the 'top' of the layer, so all other sprites in the layer will appear below it.

clone() returns a new sprite, which is identical to the current one.


Go back to CONTENTS


24. MODULE 'std/cGui'

This module provides a fairly easy way of creating a GUI. It will look like a native GUI (such as MUI), but you don't need to know anything about the native GUI system, as it behaves the same whatever native GUI is used. It is rather easier to use than MUI, but not as flexible.

Currently it uses MUI (for all Amiga OSes), but it is hoped that eventually Reaction will be used for AmigaOS4.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

24.1. Example usage

How to open a GUI window:

  DEF win:PTR TO cGuiWindow, button:PTR TO cGuiButton
  
  CreateApp().build()		->you only need to do this once!
  
  win := CreateGuiWindow('demo')
  win.beginGroupVertical()
  	win.addTextBox('label').setState('Hello world!').initFixedFont()
  	button := win.addButton('OK')
  win.endGroup()
  win.build()

How to handle events from a single open window:

  DEF quit:BOOL, item:PTR TO cGuiItem
  
  quit := FALSE
  REPEAT
  	item := WaitForChangedGuiItem()
  	IF item = NIL
  		IF win.getCloseRequest() THEN quit := TRUE
  		
  	ELSE IF item = button
  		quit := TRUE
  	ENDIF
  UNTIL quit
  win.close()

How to handle events with SEVERAL open windows:

  DEF quit:BOOL, item:PTR TO cGuiItem, itemWin:PTR TO cGuiWindow
  
  quit := FALSE
  REPEAT
  	item, itemWin := WaitForChangedGuiItem()
  	IF itemWin = win
  		->handle items of the "win" window
  		IF item = NIL
  			IF win.getCloseRequest() THEN quit := TRUE
  			
  		ELSE IF item = button
  			quit := TRUE
  		ENDIF
  	ENDIF
  UNTIL quit
  win.close()

The following example programs use it:

  Examples/std/GUI/SimpleCalculator.e
  Examples/std/GUI/SimpleModPlayer.e
  
  Examples/std/GUI/Amiga/DirList.e
  Examples/std/GUI/Amiga/NativeGuiExample.e
  Examples/std/GUI/Amiga/SimpleGameLauncher.e
  Examples/std/GUI/Amiga/Stacker.e

Released programs which are known to use it:

  PictureAlbum     ( cshandley.co.uk )
  AmiSystemRestore ( os4depot.net/?function=showfile&file=utility/misc/amisystemrestore.lha )
  Age of Thieves   ( os4depot.net/?function=showfile&file=game/board/age_of_thieves.lha )
  Ami-Ingenious    ( os4depot.net/?function=showfile&file=game/board/ami-ingenious.lha )
  FlowerWay        ( os4depot.net/?function=showfile&file=game/puzzle/flowerway.lha )
  HueFlow          ( os4depot.net/?function=showfile&file=game/puzzle/hueflow.lha )
  Ami-Scratch      ( os4depot.net/?function=showfile&file=graphics/misc/amiscratch.lha )
  Ami-Bootguard    ( os4depot.net/?function=showfile&file=utility/misc/ami-bootguard.lha )
  Ami-Lineapolis   ( www.lineapolis.dizzy.pl )

24.2. Procedures

   CreateGuiWindow(title:ARRAY OF CHAR)   RETURNS win:PTR TO cGuiWindow
  DestroyGuiWindow(win:PTR TO cGuiWindow) RETURNS nil:PTR TO cGuiWindow
   WaitForChangedGuiItem() RETURNS item:PTR TO cGuiItem, win:PTR TO cGuiWindow
  CheckForChangedGuiItem(keepPreviousChangedItems=FALSE:BOOL) RETURNS item:PTR TO cGuiItem, win:PTR TO cGuiWindow

CreateGuiWindow() creates & returns a cGuiWindow object for a new GUI window. You must supply a title (i.e. name) for your window. You must add GUI items to it, before building it. You can create as many windows as you want!

DestroyGuiWindow() destroys the supplied window, and it's contents. Your windows will be automatically destroyed when your program quits, so you may not need to use this! You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

WaitForChangedGuiItem() waits for a GUI item to be changed by the user (in any window). It then returns that item. You should find what has changed by checking the item's state (typically using the item's getState() method).

CheckForChangedGuiItem() checks whether any GUI item has been changed yet, and returns it if it has. But if nothing has changed, then it returns NIL for item. This method DOES clear the last event from all windows (except for the current one), unless you supplied TRUE for keepPreviousChangedItems.


When the GUI being used is MUI, you also get the following procedure:

  PROC AddNativeSimple(win:PTR TO cGuiWindow, object:PTIO, triggerAttr=0, triggerValue=MUIV_NotTriggerValue, label=NIL:PTIO, isFixedWidth=TRUE:BOOL, isFixedHeight=TRUE:BOOL, useInCycleChain=TRUE:BOOL) RETURNS item:PTR TO cGuiNativeSimple

AddNativeSimple() creates a GUI object for user-specified MUI code, and adds it to the GUI. As there is no addNativeSimple() method for cGuiWindow, you must use this procedure instead.

You indicate the window using win. object is the MUI object to be embedded, while label is the optional label that will be shown next to the MUI object. triggerAttr & triggerValue are the MUI attribute & value (if any) that will cause WaitForChangedGuiItem()/etc to think this object has changed. triggerAttr is also used by the object's getState() method. isFixedWidth & isFixedHeight are used to indicate whether the MUI object has a fixed width or height, and is typically called during building to determine whether any padding needs to be added to allow the GUI to be resizable. useInCycleChain is used to indicate whether the MUI object should be part of the cycle chain.

Please see the following example for how this procedure would actually be used:

  Examples/std/GUI/Amiga/NativeGuiExample.e

24.3. Methods of cGuiWindow

The cGuiWindow class is a window which contains a GUI. You must add GUI items to it, before building it. Once a GUI window is built, you cannot add any more GUI items. (In the future things may become a little more flexible.) Building the GUI will also open the window, unless you indicate otherwise. Windows may be opened & closed at any time.

GUI items are arranged within the window using groups, normally as horizontal & vertical rows. You can have groups inside of groups, which gives great flexibility. Beware that you cannot add any items to a window, until you have started a group.

Once a window is built, you must use the WaitForChangedGuiItem() or CheckForChangedGuiItem() procedure in a loop. They will tell you when the user changes a GUI item, as well as ensuring the GUI reacts to the user. You can also set GUI items to call a notification function when the user changes them.

  /* Methods of cGuiWindow */
  METHOD initAllowDropFiles() RETURNS self:PTR TO cGuiWindow
  METHOD infoAllowDropFiles() RETURNS allowDropFiles:BOOL
  METHOD initSaveID(id) RETURNS self:PTR TO cGuiWindow
  METHOD infoSaveID()   RETURNS id

initAllowDropFiles() indicates that the window should allow files to be dropped on it. This must be called before the GUI is built.

infoAllowDropFiles() returns whether initAllowDropFiles() was used or not.

initSaveID() indicates the unique ID which should be used to identify the window, so that it's position & size can be automatically saved (when the window is closed) & reloaded (when the window is created again). It is suggested that you use a quad-character, such as "Main" or "Pref", although plain numbers (perhaps ENUMerated constants) are also fine. You are not allowed to use zero as an ID.

infoSaveID() returns the ID that was given to initSaveID(), or 0 if initSaveID() was never used.

  /* more methods of cGuiWindow */
  METHOD beginGroupHorizontal(borderTitle=NILA:ARRAY OF CHAR) RETURNS item:PTR TO cGuiGroupHorizontal
  METHOD beginGroupVertical(  borderTitle=NILA:ARRAY OF CHAR) RETURNS item:PTR TO cGuiGroupVertical
  METHOD beginGroupGrid(width,borderTitle=NILA:ARRAY OF CHAR) RETURNS item:PTR TO cGuiGroupGrid
  METHOD beginGroupPage(      borderTitle=NILA:ARRAY OF CHAR) RETURNS item:PTR TO cGuiGroupPage
  METHOD endGroup()

beginGroupHorizontal() marks the beginning of a horizontal group. All items in the group will be arranged horizontally. See 24.15. Methods of cGuiGroupHorizontal & cGuiGroupVertical for more info.

NOTE: If you give a borderTitle then the whole group itself has a name, and the group will gain a border if it doesn't already have one.

beginGroupVertical() marks the beginning of a vertical group. All items in the group will be arranged vertically. See 24.15. Methods of cGuiGroupHorizontal & cGuiGroupVertical for more info.

beginGroupGrid() marks the beginning of a grid group. All items in the group will be arranged in a grid.

You must give the width of the grid in items. Items added to the group get put in the first row, as if it was a horizontal group, but after width items have been added, further items will go into the next row, etc. See 24.16. Methods of cGuiGroupGrid for more info.

beginGroupPage() marks the beginning of a multi-page group. Each item in the group is treated as a separate "page", with only one page visible at a time. Normally each item would be a horizontal or vertical group. See 24.17. Methods of cGuiGroupPage for more info.

endGroup() marks the end of the current group.

  /* more methods of cGuiWindow */
  METHOD addBreak()
  METHOD addBar(    title=NILA:ARRAY OF CHAR)
  METHOD addLabel(       label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiLabel
  METHOD addText(        label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiText
  METHOD addTextBox(     label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiTextBox
  METHOD addButton(      label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiButton
  METHOD addTick(        label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiTick
  METHOD addString(      label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiString
  METHOD addStringBox(   label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiStringBox
  METHOD addPathString(  label:ARRAY OF CHAR) RETURNS item:PTR TO cGuiPathString
  METHOD addNumberString(label:ARRAY OF CHAR, min, max) RETURNS item:PTR TO cGuiNumberString
  METHOD addSlider(      label:ARRAY OF CHAR, min, max) RETURNS item:PTR TO cGuiSlider
  METHOD addCycleChoice( label:ARRAY OF CHAR, stringChoices:ARRAY OF ARRAY OF CHAR) RETURNS item:PTR TO cGuiCycleChoice
  METHOD addRadioChoice( label:ARRAY OF CHAR, stringChoices:ARRAY OF ARRAY OF CHAR) RETURNS item:PTR TO cGuiRadioChoice
  METHOD addNative(    newItem:OWNS PTR TO cGuiNativeItem) RETURNS item:PTR TO cGuiNativeItem
  METHOD infoCurrentBuildGroup() RETURNS item:PTR TO cGuiGroupItem

addBreak() adds an invisible separator (typically in a vertical group) between items, such that the items either side of the break are not aligned. It has a similar effect to addBar(), but there is no line visible.

addBar() adds a horizontal/vertical line (in a vertical/horizontal group). Used to clearly separate items within a group, and items either side of the line are not aligned. It may be given a title. See 24.18. Methods of cGuiBar for more info.

addLabel() adds text that looks the same as the labels of other items. It is typically used for displaying a single line of text, or as an 'empty item' in a page group. See 24.19. Methods of cGuiLabel for more info.

But it can also be used to fake your own "custom item". For example you can have a horizontal group, add an item with no label, and then add the label after it, to get a "custom item" that has the label on the right (instead of the left).

addText() adds a text line, for displaying a single line of text. You must supply the item's label. It's setState() method must be used to set the string to be displayed. See 24.20. Methods of cGuiText for more info.

addTextBox() adds a text box, for displaying multiple lines of text. You must supply the item's label. It's setState() method must be used to set the string to be displayed. See 24.21. Methods of cGuiTextBox for more info.

addButton() adds a button, which the user can click on. You must supply the item's label. See 24.22. Methods of cGuiButton for more info.

addTick() adds a tick button, which the user can toggle ticked or unticked. You must supply the item's label. It's setState() method can be used to set whether it is ticked or not. See 24.23. Methods of cGuiTick for more info.

addString() adds a string input line. You must supply the item's label. It's setState() method can be used to set the shown string. See 24.24. Methods of cGuiString for more info.

addStringBox() adds a multi-line string input box. You must supply the item's label. It's setState() method can be used to set the shown string. See 24.25. Methods of cGuiStringBox for more info.

addPathString() adds a path input line, for choosing the file/dir path of something. Typically it has a button that will open a file requester. You must supply the item's label. See 24.26. Methods of cGuiPathString for more info.

addNumberString() adds a number input line. You must supply the item's label, and the min & max allowed values. It's setState() method can be used to set the shown value. See 24.27. Methods of cGuiNumberString for more info.

addSlider() adds a slider, for choosing a number. You must supply the item's label, and the min & max allowed values. It's setState() method can be used to set the slider's position. See 24.28. Methods of cGuiSlider for more info.

addCycleChoice() adds a cyclable/pop-up choice box, for choosing from several fixed options. You must supply the item's label, and the list of actual choices for stringChoices, which must end with NILA:

  e.g.  ['first choice', 'second choice', 'etc', NILA]:ARRAY_OF_CHAR

It's setState() method can be used to set the selected choice. See 24.29. Methods of cGuiCycleChoice for more info.

addRadioChoice() adds a radio-style choice list, for choosing from several fixed options. You must supply the item's label, and the list of actual choices for stringChoices, which must end with NILA:

  e.g.  ['first choice', 'second choice', 'etc', NILA]:ARRAY_OF_CHAR

It's setState() method can be used to set the selected choice. See 24.30. Methods of cGuiRadioChoice for more info.

addNative() adds an already-created native object. The object would usually be a class which inherits from cGuiNativeHost.


infoCurrentBuildGroup() returns the current group that items are being added to. You are unlikely to need this method.

  /* more methods of cGuiWindow */
  METHOD beginFixedList(columns=1, borderTitle=NILA:ARRAY OF CHAR) OF cGuiWindow RETURNS item:PTR TO cGuiFixedList
  METHOD endFixedList()
  METHOD addFixedListEntry(label:ARRAY OF CHAR) OF cGuiWindow RETURNS item:PTR TO cGuiFixedListEntry
  METHOD beginList(columns=1, title=NILA:ARRAY OF CHAR) RETURNS item:PTR TO cGuiList
  METHOD endList()
  METHOD addListEntry(label:ARRAY OF CHAR, style=GUI_STYLE_NONE, marked=FALSE:BOOL, data=0, dataBox=NIL:OWNS PTR TO class)

beginFixedList() marks the beginning of a fixed list. columns defines how many 'vertically aligned labels' (aka columns) the list has. If you give a borderTitle then the whole list itself has a name, and the list will gain a border if it doesn't already have one. You may only add fixed list entries to it. See 24.31. Methods of cGuiFixedList for more info.

endFixedList() marks the end of the fixed list.

addFixedListEntry() adds an entry to the fixed list. Each entry is a single line of text, and they appear in the order they are added. The label defines the text for ALL columns of an entry, with each column being separated by a \t character. Each entry will have a tick box if the list was defined as having selectable entries. BEWARE that it always returns item=NIL if there is no tick box. See 24.32. Methods of cGuiFixedListEntry for more info.

beginList() marks the beginning of a (dynamic) list. columns defines how many columns the list has. If you give a title then the whole list itself has a visible name. You may only add (dynamic) list entries to it. See 24.33. Methods of cGuiList for more info.

endList() marks the end of the (dynamic) list.

addListEntry() adds a single entry to the (dynamic) list. Each entry is a single line of text, and they appear in the order they are added (if no sorting order is specified for the list). The label defines the text for ALL columns of an entry, with each column being separated by a \t character. See 24.33. Methods of cGuiList for more info, and especially it's "cursor" methods.

You can also specify if the entry should be shown with a style (GUI_STYLE_ALTCOLOUR or GUI_STYLE_BOLD), or be marked. You can also store data in it, which could be a dataBox.

  /* more methods of cGuiWindow */
  METHOD build(keepWindowClosed=FALSE:BOOL)
  METHOD open()
  METHOD close()
  METHOD infoIsOpen()
  METHOD infoTitle() RETURNS title:ARRAY OF CHAR

build() takes all the added GUI items, and creates the GUI using them. It then automatically opens the window, unless you gave TRUE for keepWindowClosed.

open() opens the window, so that it is visible.

close() closes the window, so that it is hidden. The GUI items will remember their last state, so they will appear about the same when the window is reopened.

infoIsOpen() returns whether the window is open or not.

infoTitle() returns the title you set using the CreateGuiWindow() procedure.

  /* more methods of cGuiWindow */
  METHOD getLastChangedItem() RETURNS item:PTR TO cGuiItem
  METHOD setLastChangedItem(item:PTR TO cGuiItem)
  METHOD getCloseRequest(doNotClear=FALSE:BOOL) RETURNS closeRequest:BOOL
  METHOD setCloseRequest(closeRequest:BOOL)
  METHOD getQuitRequest(doNotClear=FALSE:BOOL) RETURNS quitRequest:BOOL
  METHOD setQuitRequest(quitRequest:BOOL)
  METHOD getDroppedFile(doNotClear=FALSE:BOOL) RETURNS fileDropped:ARRAY OF CHAR
  METHOD setDroppedFile(fileDropped:ARRAY OF CHAR)

getLastChangedItem() returns the last item that was changed by the user.

setLastChangedItem() allows you to change (or clear) the indication of the last item that was changed by the user.

getCloseRequest() returns whether the window has received a close request, typically due to the user clicking on the window's close button. This information will be forgotten unless you supply TRUE for doNotClear.

setCloseRequest() allows you to change (or clear) the close request indication.

getQuitRequest() returns whether the App itself has received a quit request. All windows will receive the same quit request. This information will be forgotten unless you supply TRUE for doNotClear.

setQuitRequest() allows you to change (or clear) the quit request. This is shared by all windows.

getDroppedFile() returns the path of the file dropped on the window, or NILA if there was none. Beware that files will only be detected if initAllowDropFiles() was set. This information will be forgotten unless you supply TRUE for doNotClear.

setDroppedFile() allows you to change (or clear) the file dropped indication.

  /* more methods of cGuiWindow */
  METHOD getBusy() RETURNS busy:BOOL
  METHOD setBusy(busy:BOOL)
  METHOD getPosition() RETURNS x, y
  METHOD setPosition(x, y)
  METHOD infoWidth()  RETURNS width
  METHOD infoHeight() RETURNS height
  METHOD changeSize(width, height)
  METHOD queryExtra(specific:QUAD) RETURNS value, unknown:BOOL

getBusy() & setBusy() allow you to change & retrieve the window's busy state. A busy window will not accept user input, and the user will be able to see that the window is busy (depending on the target OS & GUI, it might appear ghosted or the mouse pointer might be an hourglass).

getPosition() return the position of the window.

setPosition() changes the position of the window. This can be done before the window is opened.

infoWidth() & infoHeight() return the size of the window.

changeSize() changes the size of the window. This can be done before the window is opened.

queryExtra() allows you to retrieve OS-specific information. For example, if you give "OBJT", then it will return the Amiga MUI window object. While "SIGS" will return all the Amiga MUI signals. "WIND" will return the Amiga window pointer. "SCRN" will return the Amiga screen pointer. And "APPL" will return the Amiga MUI application object. Please only use this method as a last resort, because it will stop your code from being portable!

24.4. ABSTRACT CLASSES

The following GUI item classes are "abstract", which means they are never directly used for created objects. Instead they are used as parents of classes, to help organise similar GUI items together, and to allow them to share (some of) the same methods.

For example, the abstract cGuiInputItem class is used by all GUI items that allow the user to provide input, such as cGuiStringBox (but unlike cGuiLabel). The cGuiInputItem class (and all the classes that use it) has the setGhosted() method, which allows you to "ghost" the GUI item, preventing the user from changing it.

The name of every abstract class ends in "Item".

24.5. Methods of cGuiItem

All GUI items eventually inherit this class. The main purpose is to allow all GUI items to be given to or returned as a PTR TO cGuiItem.

  /* Methods of cGuiItem */
  METHOD setData(data) RETURNS self:PTR TO cGuiItem
  METHOD getData() RETURNS data
  METHOD infoNextInGroup() RETURNS item:PTR TO cGuiItem
  METHOD queryExtra(specific:QUAD) RETURNS value, unknown:BOOL

setData() & getData() allow you to store & retrieve one value. This is useful if you have a large number of GUI items, and want to identify them by sequential numbers rather having a variable for each of their object pointers.

infoNextInGroup() returns the next item in the current group. You probably won't need to use this.

queryExtra() allows you to retrieve OS-specific information. At the moment there are very few uses of this method. Please only use this method as a last resort, because it will stop your code from being portable!

24.6. Methods of cGuiGroupItem

All groups inherit this class, and they are GUI items themselves.

  /* Methods of cGuiGroupItem, which inherits from cGuiItem */
  METHOD initScrollable()      RETURNS self:PTR TO cGuiGroupItem
  METHOD initEqualSizedItems() RETURNS self:PTR TO cGuiGroupItem
  METHOD initUseLeastSpace()   RETURNS self:PTR TO cGuiGroupItem
  METHOD infoHasBorder()  RETURNS hasBorder:BOOL
  METHOD infoTitle()      RETURNS title:ARRAY OF CHAR
  METHOD infoSize()       RETURNS size
  METHOD infoFirstItem()  RETURNS item:PTR TO cGuiItem
  METHOD infoLastItem()   RETURNS item:PTR TO cGuiItem
  METHOD infoScrollable()      RETURNS scrollable:BOOL
  METHOD infoEqualSizedItems() RETURNS equalSizedItems:BOOL
  METHOD infoUseLeastSpace()   RETURNS useLeastSpace:BOOL
  METHOD setGhosted(ghosted:BOOL) RETURNS self:PTR TO cGuiGroupItem
  ->plus methods inherited from cGuiItem

For the inherited methods read 24.5. Methods of cGuiItem.

initScrollable() indicates that the group does not need to completely fit inside the window, and so will scroll if the window is too small.

initEqualSizedItems() indicates that all items in the group should have the same size (where possible).

initUseLeastSpace() indicates that the whole GUI group should use as little space as possible, including all items inside it. Beware that this could cause your window to have a fixed size.

infoHasBorder() returns TRUE if the group has a border, which it will if it was created with a string given to borderTitle.

infoTitle() returns the group's title, if it was not created with a non-empty string for borderTitle, otherwise it returns NILA. i.e. It returns NILA if '' was given for borderTitle.

infoSize() returns the number of items inside of the group.

infoFirstItem() returns the first item in the group.

infoLastItem() returns the last item in the group.

infoScrollable() returns whether initScrollable() was used or not.

infoEqualSizedItems() returns whether initEqualSizedItems() was used or not.

infoUseLeastSpace() returns whether initUseLeastSpace() was used or not.

setGhosted() calls the setGhosted() method on all the group's items.

24.7. Methods of cGuiLabelledItem

This is inherited by any GUI item with a label. So it is used by most GUI items!

  /* Methods of cGuiLabelledItem, which inherits from cGuiItem */
  METHOD infoLabel() RETURNS label:ARRAY OF CHAR
  ->plus methods inherited from cGuiItem

For the inherited methods read 24.5. Methods of cGuiItem.

infoLabel() returns the label that the GUI item was created with.

24.8. Methods of cGuiOutputItem

This is inherited by any GUI item that can display some data. So it is used by most GUI items! It allows you to add a pop-up description to it.

  /* Methods of cGuiOutputItem, which inherits from cGuiLabelledItem */
  METHOD initUseLeastSpace() RETURNS self:PTR TO cGuiOutputItem
  METHOD infoUseLeastSpace() RETURNS useLeastSpace:BOOL
  METHOD setPopupHint(popupHint:NULL ARRAY OF CHAR) RETURNS self:PTR TO cGuiOutputItem
  METHOD getPopupHint() RETURNS popupHint:ARRAY OF CHAR
  ->plus methods inherited from cGuiLabelledItem

For the inherited methods read 24.7. Methods of cGuiLabelledItem.

initUseLeastSpace() indicates that the GUI item should use as little space as possible. Beware that this could cause your window to have a fixed size.

NOTE: This does not yet do anything for some GUI items.

infoUseLeastSpace() returns whether initUseLeastSpace() was used or not.

setPopupHint() & getPopupHint() allow you to change & retrieve a pop-up description to help the user. getPopupHint() will return NILA if there is no hint, while setPopupHint() may be supplied NILA to clear any existing hint. But don't rely on being able to change the pop-up hint after the GUI is built.

24.9. Methods of cGuiInputItem

This is inherited by any GUI item that can accept some input from the user. It allows you to ghost the item, so that the user cannot change it. It also allows you to have a function called when the user changes it.

  /* Methods of cGuiInputItem, which inherits from cGuiOutputItem */
  METHOD setGhosted(ghosted:BOOL) RETURNS self:PTR TO cGuiInputItem
  METHOD getGhosted() RETURNS ghosted:BOOL
  METHOD setNotifyFunction(func:NULL PTR TO funcGuiNotify) RETURNS self:PTR TO cGuiItem
  METHOD getNotifyFunction() RETURNS func:PTR TO funcGuiNotify
  ->plus methods inherited from cGuiOutputItem

For the inherited methods read 24.8. Methods of cGuiOutputItem.

setGhosted() & getGhosted() allow you to change & retrieve the ghosted state. A ghosted item should not accept any user input.

setNotifyFunction() & getNotifyFunction() allow you to store & retrieve the notification function, which will be called whenever the user makes any changes. Your notification function must inherit funcGuiNotify, for example:

  FUNC yourNotification(changedItem:PTR TO cGuiItem) OF funcGuiNotify IS ...

24.10. Methods of cGuiStringItem

This is inherited by any GUI item that allows the user to change a string.

  /* Methods of cGuiStringItem, which inherits from cGuiInputItem */
  METHOD setState(string:ARRAY OF CHAR) RETURNS self:PTR TO cGuiStringItem
  METHOD getState() RETURNS string:ARRAY OF CHAR
  ->plus methods inherited from cGuiInputItem

For the inherited methods read 24.9. Methods of cGuiInputItem.

setState() & getState() allow you to change & retrieve the displayed string.

24.11. Methods of cGuiNumberItem

This is inherited by any GUI item that allows the user to change a number.

  /* Methods of cGuiNumberItem, which inherits from cGuiInputItem */
  METHOD setState(number) RETURNS self:PTR TO cGuiNumberItem
  METHOD getState() RETURNS number
  METHOD initUnit(unit:ARRAY OF CHAR) RETURNS self:PTR TO cGuiNumberItem
  METHOD infoUnit() RETURNS unit:ARRAY OF CHAR
  METHOD infoMin()  RETURNS min
  METHOD infoMax()  RETURNS max
  ->plus methods inherited from cGuiInputItem

For the inherited methods read 24.9. Methods of cGuiInputItem.

setState() & getState() allow you to change & retrieve the displayed number.

initUnit() sets the unit the number is a measure of; for example 'miles'.

infoUnit() returns the unit set using initUnit(), or NILA if none was set.

infoMin() & infoMax() returns the min & max values given when the item was created.

24.12. Methods of cGuiChoiceItem

This is inherited by any GUI item that allows the user to choose from a list of several fixed options.

  /* Methods of cGuiChoiceItem, which inherits from cGuiNumberItem */
  METHOD setState(choice) RETURNS self:PTR TO cGuiChoiceItem
  METHOD getState() RETURNS choice
  METHOD infoChoices() RETURNS choices:ARRAY OF ARRAY OF CHAR
  ->plus methods inherited from cGuiNumberItem

For the inherited methods read 24.11. Methods of cGuiNumberItem.

setState() & getState() allow you to change & retrieve the currently selected choice. The first choice is 0.

infoChoices() returns the stringChoices given when the item was created.

24.13. Methods of cGuiNativeItem

This is inherited by any native GUI item, and indicates that it is basically an object wrapper for some (typically user-specified) native GUI code.

  /* Methods of cGuiNativeItem, which inherits from cGuiItem */
  ->plus methods inherited from cGuiItem

For the inherited methods read 24.5. Methods of cGuiItem.

24.14. REAL CLASSES

The following GUI item classes are "real", which means they will be directly used for created objects. They will inherit an "abstract" class according to the kind of GUI items they are.

For example, the real cGuiStringBox class is an actual GUI item that you can add to the window. It inherits the abstract cGuiStringItem class, because it allows the user to change a string.

24.15. Methods of cGuiGroupHorizontal & cGuiGroupVertical

These are classes which arrange their GUI items in a horizontal or vertical row.

  /* Methods of cGuiGroupHorizontal & cGuiGroupVertical, which inherits from cGuiGroupItem */
  ->plus methods inherited from cGuiGroupItem

For the inherited methods read 24.6. Methods of cGuiGroupItem.

24.16. Methods of cGuiGroupGrid

This class arranges it's GUI items in a grid.

  /* Methods of cGuiGroupGrid, which inherits from cGuiGroupItem */
  ->plus methods inherited from cGuiGroupItem

For the inherited methods read 24.6. Methods of cGuiGroupItem.

24.17. Methods of cGuiGroupPage

This class is a multi-page group. Each item in it is treated as a separate "page", with only one page visible at a time. Normally each item would be a horizontal or vertical group.

  /* Methods of cGuiGroupPage, which inherits from cGuiGroupItem */
  METHOD setState(pageNumber) RETURNS self:PTR TO cGuiGroupPage
  METHOD getState() RETURNS pageNumber
  METHOD setStateItem(pageItem:PTR TO cGuiItem) RETURNS self:PTR TO cGuiGroupPage
  METHOD getStateItem() RETURNS pageItem:PTR TO cGuiItem
  METHOD infoMaxPageNum() RETURNS pageNum
  METHOD infoPageNumOfPageItem(pageItem:PTR TO cGuiItem) RETURNS pageNumber
  METHOD infoPageItemOfPageNum(pageNumber) RETURNS pageItem:PTR TO cGuiItem
  ->plus methods inherited from cGuiGroupItem

For the inherited methods read 24.6. Methods of cGuiGroupItem.

setState() & getState() allow you to change & retrieve the currently shown page, using the page number. The first page is number 0.

setStateItem() & getStateItem() allow you to change & retrieve the currently shown page, using the actual page item to be shown.

infoMaxPageNum() returns the largest page number that exists.

infoPageNumOfPageItem() returns the page number of the provided page item.

infoPageItemOfPageNum() returns the page item of the provided page number.

24.18. Methods of cGuiBar

This class is a horizontal/vertical line (in a vertical/horizontal group). It is used to clearly separate items within a group.

  /* Methods of cGuiBar, which inherits from cGuiItem */
  METHOD infoTitle() RETURNS title:ARRAY OF CHAR
  ->plus methods inherited from cGuiItem

For the inherited methods read 24.5. Methods of cGuiItem.

infoTitle() returns the title given when the item was created, or NILA if none was given.

24.19. Methods of cGuiLabel

This class shows some text that looks the same as the labels of other items.

  /* Methods of cGuiLabel, which inherits from cGuiOutputItem */
  METHOD initAlignLeft()   RETURNS self:PTR TO cGuiLabel
  METHOD initAlignCenter() RETURNS self:PTR TO cGuiLabel
  METHOD initAlignRight()  RETURNS self:PTR TO cGuiLabel
  METHOD infoAlignLeft()   RETURNS isAlignedLeft  :BOOL
  METHOD infoAlignCenter() RETURNS isAlignedCenter:BOOL
  METHOD infoAlignRight()  RETURNS isAlignedRight :BOOL
  METHOD initStyle(style)  RETURNS self:PTR TO cGuiLabel
  ->plus methods inherited from cGuiOutputItem

For the inherited methods read 24.8. Methods of cGuiOutputItem.

initAlignLeft(), initAlignCenter() & initAlignRight() indicates that the label should be left/center/right aligned. By default the alignment is the same as that used by the labels of other GUI items.

infoAlignCenter(), infoAlignCenter() & infoAlignRight() returns whether initAlignLeft(), initAlignCenter() & initAlignRight() was used or not.

initStyle() indicates that the label's text should be shown with the given style, which can be GUI_STYLE_ALTCOLOUR (typically a more noticable colour) or GUI_STYLE_BOLD. Styles of different types can be combined using the OR operator.

24.20. Methods of cGuiText

This class shows a single line of text. It usually defaults to a variable-width font, but it can use a fixed-width (mono-spaced) font if you want.

  /* Methods of cGuiText, which inherits from cGuiOutputItem */
  METHOD setState(text:ARRAY OF CHAR) RETURNS self:PTR TO cGuiText
  METHOD getState() RETURNS text:ARRAY OF CHAR
  METHOD initFixedFont()   RETURNS self:PTR TO cGuiTextBox
  METHOD initAlignCenter() RETURNS self:PTR TO cGuiTextBox
  METHOD initAlignRight()  RETURNS self:PTR TO cGuiTextBox
  METHOD infoFixedFont()   RETURNS fixedFont:BOOL
  METHOD infoAlignCenter() RETURNS isAlignedCenter:BOOL
  METHOD infoAlignRight()  RETURNS isAlignedRight :BOOL
  ->plus methods inherited from cGuiOutputItem

For the inherited methods read 24.8. Methods of cGuiOutputItem.

setState() & getState() allow you to change & retrieve the currently shown text.

initFixedFont() indicates that a fixed-width font should be used. This must be called before the GUI is built.

initAlignCenter() & initAlignRight() indicates that the shown text should be center/right aligned (rather than the default of left alignment).

infoFixedFont() returns whether initFixedFont() was used or not.

infoAlignCenter() & infoAlignRight() returns whether initAlignRight() or initAlignCenter() was used or not.

24.21. Methods of cGuiTextBox

This class shows multiple lines of text. It usually defaults to a variable-width font, but it can use a fixed-width (mono-spaced) font if you want.

  /* Methods of cGuiTextBox, which inherits from cGuiOutputItem */
  METHOD setState(text:ARRAY OF CHAR) RETURNS self:PTR TO cGuiTextBox
  METHOD getState() RETURNS text:ARRAY OF CHAR
  METHOD initFixedFont()   RETURNS self:PTR TO cGuiTextBox
  METHOD infoFixedFont()   RETURNS fixedFont:BOOL
  ->plus methods inherited from cGuiOutputItem

For the inherited methods read 24.8. Methods of cGuiOutputItem.

setState() & getState() allow you to change & retrieve the currently shown text.

initFixedFont() indicates that a fixed-width font should be used. This must be called before the GUI is built.

infoFixedFont() returns whether initFixedFont() was used or not.

24.22. Methods of cGuiButton

This class is for a button, which the user can click on. Although it has no "state", you will still be notified that is has changed when the user clicks on it.

  /* Methods of cGuiButton, which inherits from cGuiInputItem */
  METHOD initPic(picPath:ARRAY OF CHAR) RETURNS self:PTR TO cGuiInputItem
  METHOD infoPic() RETURNS picPath:ARRAY OF CHAR
  ->plus methods inherited from cGuiInputItem

For the inherited methods read 24.9. Methods of cGuiInputItem.

initPic() adds a picture to the button, next to it's label. The file path must be given in the portable format used by the cPath module, so you may need to use it's ImportFilePath() procedure first.

infoPic() returns the picture path set using initPic(), or NILA if none was set.

24.23. Methods of cGuiTick

This class is a tick button, which the user can toggle ticked or unticked.

  /* Methods of cGuiTick, which inherits from cGuiInputItem */
  METHOD setState(ticked:BOOL) RETURNS self:PTR TO cGuiTick
  METHOD getState() RETURNS ticked:BOOL
  ->plus methods inherited from cGuiInputItem

For the inherited methods read 24.9. Methods of cGuiInputItem.

setState() & getState() allow you to change & retrieve the ticked/unticked state.

24.24. Methods of cGuiString

This class is a string input line, which allows the user to change the string.

  /* Methods of cGuiString, which inherits from cGuiStringItem */
  METHOD initMaxLength(maxLength) RETURNS self:PTR TO cGuiString
  ->plus methods inherited from cGuiStringItem
  ->METHOD setState(string:ARRAY OF CHAR) RETURNS self:PTR TO cGuiString
  ->METHOD getState() RETURNS string:ARRAY OF CHAR

For the inherited methods read 24.10. Methods of cGuiStringItem.

initMaxLength() indicates that maximum number of characters that the user may enter (some implementations may be unlimited & ignore this). This must be called before the GUI is built.

24.25. Methods of cGuiStringBox

This class is a multi-line string input box, which allows the user to change the string. It usually defaults to a variable-width font, but it can use a fixed-width (mono-spaced) font if you want.

  /* Methods of cGuiStringBox, which inherits from cGuiStringItem */
  METHOD initFixedFont() RETURNS self:PTR TO cGuiStringBox
  METHOD infoFixedFont() RETURNS fixedFont:BOOL
  ->plus methods inherited from cGuiStringItem
  ->METHOD setState(string:ARRAY OF CHAR) RETURNS self:PTR TO cGuiStringBox
  ->METHOD getState() RETURNS string:ARRAY OF CHAR

For the inherited methods read 24.10. Methods of cGuiStringItem.

initFixedFont() indicates that a fixed-width font should be used. This must be called before the GUI is built.

infoFixedFont() returns whether initFixedFont() was used or not.

24.26. Methods of cGuiPathString

This class is a path input line, for choosing the file/dir path of something. Typically it has a button that will open a file requester.

It's getState() method is used to retrieve the chosen path. The path is returned in the portable format used by the cPath module, so you may need to use it's ExportPath() procedure afterwards.

It's setState() method can be used to set the shown path. The path must be given in the portable format used by the cPath module, so you may need to use it's ImportFilePath() or ImportDirPath() procedure first.

  /* Methods of cGuiPathString, which inherits from cGuiStringItem */
  METHOD initOnlyShowFolders() RETURNS self:PTR TO cGuiPathString
  METHOD initUseSaveMode()     RETURNS self:PTR TO cGuiPathString
  METHOD initShowSystemFiles() RETURNS self:PTR TO cGuiPathString

initOnlyShowFolders() indicates that the file requester should only show folders (not files). This must be called before the GUI is built.

initUseSaveMode() indicates that the file requester should use 'save mode', which means it will ask about replacing existing files. This must be called before the GUI is built.

initShowSystemFiles() indicates that the file requester should show system files (which on the Amiga means show .info files). This must be called before the GUI is built.

  /* more methods of cGuiPathString */
  METHOD infoOnlyShowFolders() RETURNS onlyShowFolders:BOOL
  METHOD infoUseSaveMode()     RETURNS useSaveMode:BOOL
  METHOD infoShowSystemFiles() RETURNS showSystemFiles:BOOL
  ->plus methods inherited from cGuiStringItem
  ->METHOD setState(string:ARRAY OF CHAR) RETURNS self:PTR TO cGuiPathString
  ->METHOD getState() RETURNS string:ARRAY OF CHAR

For the inherited methods read 24.10. Methods of cGuiStringItem.

infoOnlyShowFolders() returns whether initOnlyShowFolders() was used or not.

infoUseSaveMode() returns whether initUseSaveMode() was used or not.

infoShowSystemFiles() returns whether initShowSystemFiles() was used or not.

24.27. Methods of cGuiNumberString

This class is a number input line, which only allows the user to enter a number. It also ensures that the number is within an allowed range.

  /* Methods of cGuiNumberString, which inherits from cGuiNumberItem */
  ->plus methods inherited from cGuiNumberItem
  ->METHOD setState(number) RETURNS self:PTR TO cGuiNumberString
  ->METHOD getState() RETURNS number
  ->METHOD initUnit(unit:ARRAY OF CHAR) RETURNS self:PTR TO cGuiNumberString
  ->METHOD infoUnit() RETURNS unit:ARRAY OF CHAR
  ->METHOD infoMin()  RETURNS min
  ->METHOD infoMax()  RETURNS max

For the inherited methods read 24.11. Methods of cGuiNumberItem.

24.28. Methods of cGuiSlider

This class is a slider, for choosing a number within an allowed range.

  /* Methods of cGuiSlider, which inherits from cGuiNumberItem */
  ->plus methods inherited from cGuiNumberItem
  ->METHOD setState(number) RETURNS self:PTR TO cGuiSlider
  ->METHOD getState() RETURNS number
  ->METHOD initUnit(unit:ARRAY OF CHAR) RETURNS self:PTR TO cGuiSlider
  ->METHOD infoUnit() RETURNS unit:ARRAY OF CHAR
  ->METHOD infoMin()  RETURNS min
  ->METHOD infoMax()  RETURNS max

For the inherited methods read 24.11. Methods of cGuiNumberItem.

24.29. Methods of cGuiCycleChoice

This class is a cyclable/pop-up choice box, for choosing from several fixed options.

  /* Methods of cGuiCycleChoice, which inherits from cGuiChoiceItem */
  ->plus methods inherited from cGuiChoiceItem
  ->METHOD setState(choice) RETURNS self:PTR TO cGuiCycleChoice
  ->METHOD getState() RETURNS choice
  ->METHOD infoChoices() RETURNS choices:ARRAY OF ARRAY OF CHAR

For the inherited methods read 24.12. Methods of cGuiChoiceItem.

24.30. Methods of cGuiRadioChoice

This class is a radio-style choice list, for choosing from several fixed options.

  /* Methods of cGuiRadioChoice, which inherits from cGuiChoiceItem */
  ->plus methods inherited from cGuiChoiceItem
  ->METHOD setState(choice) RETURNS self:PTR TO cGuiRadioChoice
  ->METHOD getState() RETURNS choice
  ->METHOD infoChoices() RETURNS choices:ARRAY OF ARRAY OF CHAR

For the inherited methods read 24.12. Methods of cGuiChoiceItem.

24.31. Methods of cGuiFixedList

This class is a scrollable list of entries, where each entry is a single line of text. If the list is defined as having selectable entries, then each entry will have a tick box.

List entries canNOT be added after the GUI is built, nor can they be modified, hence the name "fixed list".

It is not suitable for very large lists, because every entry is built out of several other cGui items. This means that large lists will take a long time to build, and will probably use a lot of memory.

The main advantage of cGuiFixedList over the dynamic lists (of cGuiList) is that it is built using other GUI items, and so is much more likely to be supported by any newly-added GUI systems (on say Linux or whatever).

  /* Methods of cGuiFixedList, which inherits from cGuiGroupItem */
  METHOD initSelectableEntries(multiSelect=FALSE:BOOL) RETURNS self:PTR TO cGuiFixedList
  METHOD initColumnAlignment(alignment:ARRAY OF CHAR)  RETURNS self:PTR TO cGuiFixedList
  METHOD initColumnTitles(titles:ARRAY OF CHAR)        RETURNS self:PTR TO cGuiFixedList
  METHOD infoSelectableEntries() RETURNS selectable:BOOL, multiSelect:BOOL
  METHOD infoColumnAlignment()   RETURNS alignment:ARRAY OF CHAR
  METHOD infoColumnTitles()      RETURNS titles:ARRAY OF CHAR
  METHOD infoColumns()           RETURNS columns
  METHOD infoSelectionCount()       RETURNS selectionCount
  METHOD infoSingleSelectionEntry() RETURNS item:PTR TO cGuiFixedListEntry
  METHOD setMultiSelect(multiSelect:BOOL)
  METHOD getMultiSelect() RETURNS multiSelect:BOOL
  ->plus methods inherited from cGuiGroupItem
  ->METHOD infoHasBorder() RETURNS hasBorder:BOOL
  ->METHOD infoTitle() RETURNS title:ARRAY OF CHAR
  ->METHOD infoSize()  RETURNS size
  ->METHOD infoFirstItem() RETURNS item:PTR TO cGuiFixedListEntry
  ->METHOD infoLastItem()  RETURNS item:PTR TO cGuiFixedListEntry
  ->METHOD setGhosted(ghosted:BOOL)
  
  ->the following inherited methods are NOT supported
  ->METHOD initScrollable()      RETURNS self:PTR TO cGuiFixedList
  ->METHOD initEqualSizedItems() RETURNS self:PTR TO cGuiFixedList
  ->METHOD infoScrollable()      RETURNS scrollable:BOOL
  ->METHOD infoEqualSizedItems() RETURNS equalSizedItems:BOOL

For the inherited methods read 24.6. Methods of cGuiGroupItem.

initSelectableEntries() indicates that the list's entries are selectable by the user. Normally selecting a second entry will cause the first to become unselected, but if you give TRUE for multiSelect then all entries stay selected (until unselected). This method must be called before any entries are added.

initColumnAlignment() indicates how the columns should be aligned. alignment is a string, with one character per column, where "L" means left aligned, "C" means center aligned, and "R" means right aligned. Thus 'LLCR' means left align the first two columns, then center the next column, then right align the next column. By default everything is left aligned.

initColumnTitles() indicates what title should appear at the top of each column. The titles defines the text for ALL columns, with each column being separated by a \t character. BEWARE that the titles are a kludge, as they actually appear inside the scrollable list, and so they will not be visible when it is scrolled vertically.

infoSelectableEntries() returns whether initSelectableEntries() was used or not. It also returns what multiSelect was supplied when it was called.

infoColumnAlignment() returns the "alignment" string which represents how the columns will be aligned (see the initColumnAlignment() description for more details).

infoColumnTitles() returns the "titles" string which was given to initColumnTitles(), or NILA if none was given.

infoColumns returns the number of columns the list was created with.

infoSelectionCount() returns how many entries are selected.

infoSingleSelectionEntry() returns the selected entry, or NIL if nothing is selected. It may only be used when multiSelect=FALSE.

setMultiSelect() & getMultiSelect() allow you to change & retrieve multiSelect, but only if you used initSelectableEntries(TRUE).

24.32. Methods of cGuiFixedListEntry

This class is a single line of text, which appears inside a scrollable list. Optionally it can be selectable, which means that it will have a tick box next to the text.

  /* Methods of cGuiFixedListEntry, which inherits from cGuiItem */
  METHOD setState(ticked:BOOL)
  METHOD getState()       RETURNS ticked:BOOL
  METHOD infoLabel()      RETURNS label:ARRAY OF CHAR
  METHOD infoIndex()      RETURNS index
  METHOD initStyle(style) RETURNS self:PTR TO cGuiFixedListEntry
  METHOD setGhosted(ghosted:BOOL)
  METHOD getGhosted() RETURNS ghosted:BOOL
  METHOD setNotifyFunction(func:NULL PTR TO funcGuiNotify)
  METHOD getNotifyFunction() RETURNS func:PTR TO funcGuiNotify
  ->plus methods inherited from cGuiItem
  ->setData(data) RETURNS self:PTR TO cGuiFixedListEntry
  ->getData() RETURNS data
  ->infoNextInGroup() RETURNS item:PTR TO cGuiFixedListEntry

For the inherited methods read 24.5. Methods of cGuiItem.

setState() & getState() allow you to change & retrieve the selection state.

infoLabel() returns the label that the GUI item was created with.

infoIndex() returns the unique number used to identify this entry. The first entry is 0, the second is 1, and so on. (If this is not a convenient way to identify entries, don't forget that you can use setData() & getData() as with any GUI item.)

initStyle() indicates that the line of text should be shown with the given style, which can be GUI_STYLE_ALTCOLOUR (typically a more noticable colour) or GUI_STYLE_GHOSTEDCOLOUR (typically a less noticable colour) or GUI_STYLE_BOLD. Styles of different types can be combined using the OR operator, but you can only use one colour.

setGhosted() & getGhosted() are the same as in 24.9. Methods of cGuiInputItem.

setNotifyFunction() & getNotifyFunction() are the same as in 24.9. Methods of cGuiInputItem.

24.33. Methods of cGuiList

This class is a scrollable list of entries, where each entry is a single line of text. If the list is defined as having selectable entries, then each entry can be (un)highlighted by clicking it.

List entries may be added before or after the GUI is built, and they can be modified (typically via the list's "cursor" methods). The list can also be sorted, which changes the order of the entries. This is why the list is described as "dynamic", and is a big advantage over cGuiFixedList.

It is suitable for very large lists, as the entries are stored & rendered in an efficient manner.


Several words have very specific meanings:

initSelectableEntries() indicates that the list's entries are selectable by the user. Normally selecting a second entry will cause the first to become unselected, but if you give TRUE for multiSelect then all entries stay selected (until unselected). Normally multi-selected entries stay selected until unselected by the user, but if you give TRUE for autoUnselect then any new selection(s) will automatically unselect any previous selections.

initColumnTitles() indicates what title should appear at the top of each column. The titles defines the text for ALL columns, with each column being separated by a \t character.

initColumnAlignment() indicates how the columns should be aligned. alignment is a string, with one character per column, where "L" means left aligned, "C" means center aligned, and "R" means right aligned. Thus 'LLCR' means left align the first two columns, then center the next column, then right align the next column. By default everything is left aligned.

initColumnSortType() indicates the how each column should be used for sorting. type is a string, with one character per column, where "I" means case Insensitive, "S" means case Sensitive, and "N" means Number (so that it is treated as a number). Thus 'IISN' means the first two columns should use case insensitive sorting, then the next column should use case sensitive sorting, then the next column should be sorted as a number. By default everything is sorted case insensitively.

infoSelectableEntries() returns whether initSelectableEntries() was used or not. It also returns what multiSelect & autoUnselect was supplied when it was called.

infoColumnTitles() returns the "titles" string which was given to initColumnTitles(), or NILA if none was given.

infoColumnAlignment() returns the "alignment" string which represents how the columns will be aligned (see the initColumnAlignment() description for more details).

infoColumnSortType() returns the "type" string which represents how the columns will be sorted (see the initColumnSortType() description for more details).

infoColumns returns the number of columns the list was created with.

infoSelectionCount() returns how many entries are selected.

infoSingleSelectionEntry() returns the selected entry, or NIL if nothing is selected. It may only be used when multiSelect=FALSE.

infoTitle() returns the title the list was created with, or NILA if none was specified.

infoSize() returns the number of entries in the list.

queryExtra() allows you to retrieve OS-specific information. For example, if you give "OBJT", then it will return the Amiga MUI object. Please only use this method as a last resort, because it will stop your code from being portable!

  /* more methods of cGuiList */
  METHOD addEntry(labels:OWNS STRING, style=GUI_STYLE_NONE, marked=FALSE:BOOL, data=0, dataBox=NIL:OWNS PTR TO class, moveCursorToEntry=FALSE:BOOL)
  METHOD update(  labels:OWNS STRING)
  METHOD addEntryF(func:PTR TO fGuiListEntries)
  METHOD updateF(  func:PTR TO fGuiListEntries)

addEntry() adds an entry to the list. The entry's position depends on the list's sorting mode, but it will add it to the bottom of an unsorted list. You can add more than one entry at a time, by making labels a linked-list of STRINGs (see Link() in section 5.10. E-strings).

Beware that the list takes ownership of the labels e-strings, so you must not destroy (nor access) them yourself.

You can also specify if the entry should be shown with an style (GUI_STYLE_ALTCOLOUR or GUI_STYLE_BOLD), or be marked. You can also store data in it, which could be a dataBox. Beware that if you are adding a linked-list of e-STRINGs, then only the first one will get dataBox.

If you supply TRUE for moveCursorToEntry then the list's cursor will be left on the added entry. If labels lists several entries, then the cursor is left on the first one.

Note that this is the only method which can change the list's contents before the GUI is built.

update() replaces the entire contents of the list with the entries given by the linked-list of e-string labels. This is better than deleting all entries & then adding them, because (a) already-existing entries stay selected/marked/etc, (b) it should be quicker, and (c) the user won't see all the entries disaappear & then reappear (rather new entries will be added & missing entries will be removed).

However, it is required that the list is sorted. And it is assumed that entries which are equal for sorting purposes, are actually the same entry, and thus the un-sorted parts of a label are updated with that given in the new label. You can use setSortByFunction() to ensure this makes sense, if setSortByColumn() isn't sufficient. Use setSortByFunction(fGuiListSort) if the entire label defines a unique entry.

Beware that the list takes ownership of the labels e-strings, so you must not destroy (nor access) them yourself.

addEntryF() adds multiple entries to the list. The supplied function is called, and every entry it returns is added to the list, stopping only when it returns labels=NILS. Your function must inherit fGuiListEntries, for example:

  FUNC yourEntries() OF fGuiListEntries RETURNS label:OWNS STRING, style, marked:BOOL, data, dataBox:OWNS PTR TO class IS ...

See addEntry() for information about the returned variables. The main benefit of addEntryF() over addEntry() is that you can add multiple entries at the same time while still giving each entry unique values for style, marked, data & dataBox.

updateF() replaces the entire contents of the list with the entries returned by calling the supplied function (until it returns labels=NILS). It is better than deleting all entries & then adding them, for the same reasons as update(). It is better than update() in that each entry can have unique values for style, marked, data & dataBox. Your function must follow the same restrictions as for addEntryF().

  /* more methods of cGuiList */
  METHOD setSortByNone()
  METHOD getSortByNone() RETURNS isSortByNone:BOOL
  METHOD setSortByColumn(column, reverse=FALSE:BOOL)
  METHOD getSortByColumn() RETURNS isSortByColumn:BOOL, column, reverse:BOOL
  METHOD setSortByUser(initialColumn=0, initialReverse=FALSE:BOOL)
  METHOD getSortByUser() RETURNS isSortByUser:BOOL, column, reverse:BOOL
  METHOD setSortByFunction(sortFunc:PTR TO fGuiListSort)
  METHOD getSortByFunction() RETURNS isSortByFunction:BOOL, sortFunc:PTR TO fGuiListSort

setSortByNone() & getSortByNone() allow you to make the list unsorted (which is the default), and check whether this is the case. When the list is unsorted you can use the cursor_beforeInsert() & cursor_afterInsert() methods.

setSortByColumn() & getSortByColumn() allow you to make the list sorted by a particular column, and check whether this is the case. column indicates which column is sorted (the first column is 0). reverse indicates that the column is using the opposite of the normal sorting order.

setSortByUser() & getSortByUser() allow you to let the user sort the list how they like, and check whether this is the case. initialColumn & initialReverse indicate how the list should initially be sorted. column & reversed indicate how it is currently sorted.

setSortByFunction() & getSortByFunction() allow you to make the list sorted in an arbitrary manner, and check whether this is the case. The sortFunc function is called to compare the labels of two entries, to see if one entry should come before or after another entry.

A skeleton function looks like this:

  FUNC yourSortFunc(firstLabel:ARRAY OF CHAR, secondLabel:ARRAY OF CHAR, firstData, secondData, firstDataBox:PTR TO class, secondDataBox:PTR TO class) OF fGuiListSort RETURNS order:RANGE -1 TO 1
  ENDFUNC

Conceptually this function returns the Sign() of "second - first", although the implementation is up to you. For example, you might implement it like this:

  order := OstrCmpNoCase(firstLabel, secondLabel)

More complex implementations might compare particular columns, by searching for \t characters within each label. Or if the entries contain Data or DataBox values, then it might compare these.

For getSortByFunction(), note that although isSortByFunction will be FALSE for SortByColumn & SortByUser, it will still return a valid sortFunc function that you can use.

  /* more methods of cGuiList */
  METHOD getEventSelectionChanged(doNotClear=FALSE:BOOL) RETURNS selectionChanged:BOOL
  METHOD setEventSelectionChanged(selectionChanged:BOOL)
  METHOD getEventDoubleClickedEntry(moveCursorToEntry=FALSE:BOOL, doNotClear=FALSE:BOOL) RETURNS label:ARRAY OF CHAR
  METHOD setEventDoubleClickedEntry()
  METHOD getEventSortedByUser(doNotClear=FALSE:BOOL) RETURNS sortedByUser:BOOL, column, reverse:BOOL
  METHOD setEventSortedByUser(sortedByUser:BOOL)

getEventSelectionChanged() returns whether the list's selections were changed by the user. This information will be forgotten unless you supply TRUE for doNotClear.

setEventSelectionChanged() allows you to change (or clear) the list selection indication.

getEventDoubleClickedEntry() returns the last entry that was double-clicked by the user, or NILA if none was. If you supply TRUE for moveCursorToEntry, then the cursor will be moved to the double-clicked entry. This information will be forgotten unless you supply TRUE for doNotClear.

setEventDoubleClickedEntry() allows you to change (or clear) the double-clicked indication.

getEventSortedByUser() returns whether the list was sorted by the user, and if so then how it is now sorted. This information will be forgotten unless you supply TRUE for doNotClear.

setEventSortedByUser() allows you to change (or clear) the sorted event indication.

  /* more methods of cGuiList */
  METHOD cursor_gotoStart() RETURNS success:BOOL
  METHOD cursor_gotoEnd()   RETURNS success:BOOL
  METHOD cursor_gotoNext(steps=1) RETURNS movedSteps
  METHOD cursor_gotoPrev(steps=1) RETURNS movedSteps
  METHOD cursor_gotoFirstSelected() RETURNS success:BOOL
  METHOD cursor_gotoNextSelected()  RETURNS success:BOOL
  METHOD cursor_find(label:ARRAY OF CHAR, noCase=FALSE:BOOL, compareLength=0, continueFromLastMatch=FALSE:BOOL) RETURNS success:BOOL
  METHOD cursor_walkToStart() RETURNS oldPosition
  METHOD cursor_isAtStart() RETURNS isAtStart:BOOL
  METHOD cursor_isAtEnd()   RETURNS isAtEnd:BOOL

cursor_gotoStart() moves the cursor to the first entry of the list. It returns FALSE if the list is empty.

cursor_gotoEnd() moves the cursor to the last entry of the list. It returns FALSE if the list is empty.

cursor_gotoNext() moves the cursor forward by steps entries. steps may be zero or even negative. It returns the actual number of moved steps, which may be less than requested (or even zero) if the end of the list was reached.

cursor_gotoPrev() moves the cursor backwards by steps entries. steps may be zero or even negative. It returns the actual number of moved steps, which may be less than requested (or even zero) if the start of the list was reached.

cursor_gotoFirstSelected() moves the cursor to the first selected entry. It returns FALSE if there were no selected entries.

cursor_gotoNextSelected() moves the cursor to the next selected entry. It returns FALSE if there were no selected entries.

cursor_find() moves to the cursor to the entry matching the given label, returning FALSE if no match was found. Normally the matching is case sensitive, but if TRUE is given for noCase then it is case insensitive. If compareLength is >0 then only the first compareLength characters of label & the entry are compared. If compareLength is <0 then only the last -compareLength characters of label & the entry are compared. Normally the search starts from the beginning of the list, but if TRUE is given for continueFromLastMatch then it continues the search from the current cursor position, to look for another match.

cursor_walkToStart() goes to the first entry of the list, and returns how many entries it passed through (and thus what it's original position was). This is useful if you need to move the cursor & want to restore it's position later, but beware that it may be slow depending on how the target GUI implements a list. If the list is empty then it returns -1.

cursor_isAtStart() returns whether or not the cursor is on the first entry of the list.

cursor_isAtEnd() returns whether or not the cursor is on the last entry of the list.

  /* more methods of cGuiList */
  METHOD cursor_setLabel(label:ARRAY OF CHAR, goto0newSortedLocation1next2prev=0)
  METHOD cursor_getLabel() RETURNS label:ARRAY OF CHAR
  METHOD cursor_setStyle(style)
  METHOD cursor_getStyle() RETURNS style
  METHOD cursor_setState(selected:BOOL)
  METHOD cursor_getState() RETURNS selected:BOOL
  METHOD cursor_setMarked(marked:BOOL)
  METHOD cursor_getMarked() RETURNS marked:BOOL
  METHOD cursor_setData(data)
  METHOD cursor_getData() RETURNS data
  METHOD cursor_setDataBox(data:OWNS PTR TO class)
  METHOD cursor_getDataBox() RETURNS data:PTR TO class

cursor_setLabel() & cursor_getLabel() allow you to change & retrieve the label of the current entry.

When the label of an entry is changed in a sorted list, the entry will be moved to a different location. By default the cursor will follow the entry to it's new location, but you can use goto0newSortedLocation1next2prev to do something different (supply 1 to move the cursor to the next entry (before the entry is moved), or 2 to move the cursor to the previous entry).

cursor_setStyle() & cursor_getStyle() allow you to change & retrieve the style of the current entry. When style is GUI_STYLE_ALTCOLOUR, the text should appear in an alternative (typically more noticable) colour. When style is GUI_STYLE_GHOSTEDCOLOUR then the text should appear in a ghosted (typically less noticable) colour. When style is GUI_STYLE_BOLD then the text will be bold. Styles of different types can be combined using the OR operator, but you can only use one colour.

cursor_setState() & cursor_getState() allow you to change & retrieve the selection state of the current entry.

cursor_setMarked() & cursor_getMarked() allow you to change & retrieve whether or not the current entry is marked.

cursor_setData() & cursor_getData() allow you to store & retrieve one piece of data for the current entry. If you need to store a PTR, ARRAY, STRING or LIST, then please use setDataBox() & getDataBox() instead.

cursor_setDataBox() & cursor_getDataBox() allow you to store & retrieve one box (containing a piece of data) for the current entry. This box typically contains some data related to the entry. Note that the box is automatically deallocated.

Although you can store any class object, it is expected that typically you will store a "box", and thus will use the 'std/pBox' module. Here is a typical usage example:

  myList.cursor_setDataBox(BoxARRAY('a string is an array!'))
  Print('The entry contains "\s"\n', UnboxARRAY(myList.cursor_getDataBox()))

Here is a slightly more complex example:

  myList.cursor_setDataBox(BoxSTRING(NEW 'this is turned into an e-STRING by NEW'))
  Print('The entry contains "\s"\n', UnboxSTRING(myList.cursor_getDataBox()))
  /* more methods of cGuiList */
  METHOD cursor_beforeInsert(labels:OWNS STRING, style=GUI_STYLE_NONE, marked=FALSE:BOOL, data=0, dataBox=NIL:OWNS PTR TO class)
  METHOD cursor_afterInsert( labels:OWNS STRING, style=GUI_STYLE_NONE, marked=FALSE:BOOL, data=0, dataBox=NIL:OWNS PTR TO class)
  METHOD cursor_destroy(gotoPrev=FALSE:BOOL) RETURNS movedToExpectedEntry:BOOL
  METHOD cursor_remove( gotoPrev=FALSE:BOOL) RETURNS label:OWNS STRING, movedToExpectedEntry:BOOL

cursor_beforeInsert() & cursor_afterInsert() allow you to insert entries before or after the current cursor position. You can insert more than one entry at a time by supplying a linked-list of e-strings.

This may only be used on an UNsorted list.

Beware that the list takes ownership of the labels e-strings, so you must not destroy (nor access) them yourself.

You can also specify if the entry should be shown with a style, or be marked. You can also store data in it, which could be a dataBox. Beware that if you are adding a linked-list of e-STRINGs, then only the first one will get dataBox.

cursor_destroy() allows you to destroy the current entry. The cursor is moved to the next entry, unless you give TRUE to gotoPrev (in which case it is moved to the previous entry). If the cursor could not be moved in the expected direction (due to being at the edge of the list), then it will return FALSE for movedToExpectedEntry.

cursor_remove() allows you to remove the current entry. It is the same as the cursor_destroy() method, except that it returns the entry's label (as an e-string that you take ownership of & therefore must take care to destroy it).

  /* more methods of cGuiList */
  METHOD markAll()
  METHOD marked_unmark()
  METHOD marked_setStyle(style)
  METHOD marked_setState(selected:BOOL)
  METHOD marked_destroy(gotoPrevIfRemoved=FALSE:BOOL) RETURNS entriesDestroyed
  METHOD marked_remove( gotoPrevIfRemoved=FALSE:BOOL) RETURNS labels:OWNS STRING
  ->plus methods inherited from cGuiInputItem

For the inherited methods read 24.9. Methods of cGuiInputItem.

markAll() is a simple way to mark all the entries in the list. It is expected that you will do this before calling one of the "marked" methods (see below).

marked_unmark() allows you to unmark all entries.

marked_setStyle() allows you to set all marked entries to the same style.

marked_setState() allows you to set all marked entries to the same selection state.

marked_destroy() allows you to destroy all the marked entries. It returns the number of destroyed entries. If the cursor is on an entry being destroyed, then it will be moved to the next entry unless TRUE is given for gotoPrevIfRemoved (in which case it will be moved to the previous entry).

marked_remove() allows you to remove all the marked entries. It is the same as the marked_destroy() method, except that it returns all of the entry's labels (as a linked-list of e-strings, which you take ownership of).

24.34. Methods of cGuiNativeSimple

This class is a wrapper for any native GUI code that has been added using the AddNativeSimple() procedure.

  /* Methods of cGuiNativeSimple, which inherits from cGuiNativeItem */
  METHOD setState(state)
  METHOD getState() RETURNS state
  ->plus methods inherited from cGuiNativeItem

For the inherited methods read 24.13. Methods of cGuiNativeItem.

setState() & getState() allow you to change & retrieve the state of the GUI element (atleast where such state can be represented by a single VALUE).

When the GUI being used is MUI, they allow you to change & retrieve the MUI attribute specified by the triggerAttr parameter given to AddNativeSimple().

24.35. Methods of cGuiNativeHost

This class is used as the parent of any "native GUI class", which the user can create to wrapper some native GUI code. Here is what a native Tick class might look like:

  CLASS cGuiNativeTick OF cGuiNativeHost
     initialState:BOOL
     label :OWNS STRING
  ENDCLASS

  /* Methods of cGuiNativeHost, which inherits from cGuiNativeItem */
  METHOD initShared()
  METHOD infoGroupIsOfClassType(type:CLASSTYPE) RETURNS isOfClassType:BOOL
  ->plus methods inherited from cGuiNativeItem

For the inherited methods read 24.13. Methods of cGuiNativeItem.

initShared() must be called at the end of the constructor.

infoGroupIsOfClassType() allows the class to check what kind of group it is inside. This can be used during building to choose the best native GUI code.


There are also a whole bunch of methods that are specific to the native GUI system being used:

  /* Methods of cGuiNativeHost, which are specific to MUI */
  METHOD infoIsFixedWidth()  RETURNS
  METHOD infoIsFixedHeight() RETURNS
  METHOD build() RETURNS muiItems:OWNS LIST, object:PTIO, label:PTIO
  METHOD setupNotify(watchObject:PTIO, actionHook:PTR TO hook, param:ILIST)
  METHOD infoUseInCycleChain() RETURNS useInCycleChain:BOOL
  METHOD infoObject() RETURNS object:PTIO
  METHOD infoLabel()  RETURNS label :PTIO 

infoIsFixedWidth() & infoIsFixedHeight() is used to indicate whether the MUI object has a fixed width or height. It is typically called during building (before build() is called) to determine whether any padding needs to be added to allow the GUI to be resizable.

build is used to create the MUI elements, as previously described in it's constructor & any subsequent set or init method calls. Here is how it might look for a CheckMark:

  PROC build() OF cGuiNativeTick RETURNS muiItems:OWNS LIST, object:PTIO, label:PTIO
     muiItems := NEW [Child, label := Label2(self.label), Child, object := CheckMark(IF self.initialState THEN MUI_TRUE ELSE MUI_FALSE)]
  ENDPROC

setupNotify() is used to set-up notification for the MUI object, so that WaitForChangedGuiItem()/etc knows when the user has interacted with it. This method is automatically called after build(). Here is how it might look for a CheckMark:

  PROC setupNotify(watchObject:PTIO, actionHook:PTR TO hook, param:ILIST) OF cGuiNativeTick
     muim_Notify_action(watchObject, MUIA_Selected, MUIV_EveryTime, actionHook, param)
  ENDPROC

infoUseInCycleChain() is used to indicate whether the MUI object should be part of the cycle chain. This method is automatically called after build().

infoObject() returns the MUI object created by the build() method. You might need to know this when implementing new methods for your class, such as getState() or setState() methods.

infoLabel() returns the MUI label object (if any) created by the build() method. You might need to know this when implementing new methods for your class.

Please see the following example for how this class would actually be used:

  Examples/std/GUI/Amiga/NativeGuiExample.e


Go back to CONTENTS


25. MODULE 'std/cMusic

This module provides an easy way of playing music, which is suitable for games & multimedia.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

NOTE: Currently it can only load & play Protracker music (using the ptplay.library). I expect to add MP3 support in the future.

25.1. Example usage

How to play music:

  DEF music:PTR TO cMusic
  
  CreateApp().build()		->you only need to do this once!
  music := LoadMusic('MyMusic.mod')
  music.play()

How to wait for the music to finish playing:

  music.waitForPlayToFinish()

A more flexible way to wait for the music to finish playing:

  WHILE WaitForMusicEvent() <> music DO EMPTY

Here's another way to play music:

  CreateApp().build()		->you only need to do this once!
  StoreMusic('test', 0, LoadMusic('MyMusic.mod'))
  UseMusic('test', 0).play()

The following example programs use it:

  Examples/std/GUI/SimpleModPlayer.e
  Examples/std/Multimedia/ShadowOfTheBlitz_Scroller/SOTB.e
  Examples/std/Multimedia/ShootEmUp/ShootEmUp.e
  Examples/std/Multimedia/StarsDemo.e

25.2. Procedures

  PROC    LoadMusic(file:ARRAY OF CHAR, allowReturnNIL=FALSE:BOOL) RETURNS music:PTR TO cMusic
  PROC DestroyMusic(music:PTR TO cMusic) RETURNS nil:PTR TO cMusic
  PROC  WaitForMusicEvent() RETURNS music:PTR TO cMusic
  PROC CheckForMusicEvent() RETURNS music:PTR TO cMusic
  PROC StoreMusic(name:ARRAY OF CHAR, number, music:OWNS PTR TO cMusic) RETURNS storedMusic:PTR TO cMusic
  PROC   UseMusic(name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS music:PTR TO cMusic

LoadMusic() loads the given music, and returns a cMusic object for it. The file path must be given in the portable format used by the cPath module, so you may need to use it's ImportFilePath() procedure first. If the file could not be loaded, then an exception will be raised (unless TRUE was given to allowReturnNIL, in which case NIL would be returned instead).

DestroyMusic() destroys the supplied music object. Your music will be automatically destroyed when your program quits, so you may not need to use this! You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

WaitForMusicEvent() waits for any playing music to stop (unless one has already stopped), and then returns that music. Note that it will only remember the most recent events (typically the last 100), so ensure that you watch for events regularly.

CheckForMusicEvent() checks if any previously playing music has stopped, and returns that music. If no music has stopped, then it returns NIL.

StoreMusic() & UseMusic() allow you to store & retrieve music using a name string, and optionally a number. The string must be an 'immediate string', not one you have created. It returns the stored music, so you can use it straight away. Here's an example of how you might use it:

  StoreMusic('title', 0, LoadMusic('music/Title.mod'))
  
  UseMusic('title', 0).play()

If you try to store more than one music with the same name & number combination, then an exception will be raised. This is to prevent you accidentally reusing them. And if you try to use a non-existant music, then an exception will be raised; unless you gave TRUE for allowReturnNIL, in which case NIL will be returned.

25.3. Methods of cMusic

The cMusic class is music which can be played. You can only play one piece of music at a time. Playing a new piece of music will stop the previously playing one.

  /* Methods of cMusic */
  METHOD play(playCount=1)
  METHOD stop()
  METHOD infoLength()    RETURNS milliSeconds
  METHOD infoIsPlaying() RETURNS isPlaying:BOOL
  METHOD waitForPlayToFinish()
  METHOD setVolume(volume) RETURNS music:PTR TO cMusic
  METHOD getVolume() RETURNS volume

play() starts playing the music, using the given parameters. playCount indicates how many times the music should be played (back to back). Use 0 if you want the music to play forever.

stop() stops the music from playing.

infoLength() returns the length of the music in milliseconds.

infoIsPlaying() returns whether or not the music is currently playing.

waitForPlayToFinish() pauses until the music has stopped playing.

setVolume() & getVolume() allow you to change & retrieve volume. This is how loud the music will be played, where 100 is maximum volume, 50 is half volume, 0 is silent, and so on. It is used by subsequent play() calls, and it also affects the music if it is currently playing.


Go back to CONTENTS


26. MODULE 'std/cPath'

This module provides easy access to files & directories. It hides the host OS's path format (and any DOS quirks). So it should work identically whatever OS is used, and thus allow the same file/directory code everywhere.

As you typically only want to handle paths, or files, or directories, but not all three, this module has been split into three smaller modules, so that you can reduce your executable size & compile time. These modules are:

Supported OSes: All.

Note that you automatically get 'std/cPath_shared' if you use either 'std/cPath_File' or 'std/cPath_Dir'.

26.1. Example usage

While the module has many procedures & methods (to do almost anything you could ever want), these examples should cover the main things you might want to do.

How to turn a host OS path into a portable path that we can use:

  DEF portablePath:STRING
  
  portablePath := ImportFilePath('path of some file')
  Print('The portable path is "\s".\n', portablePath)
  IF ExistsPath(portablePath) THEN Print('It exists!\n')
  
  END portablePath

How to create or open a directory:

  DEF dir:PTR TO cDir
  
  NEW dir.new()
  IF dir.open('examplePortablePath/')
  	->use the directory now
  	IF dir.getAttributes() AND CPA_DELETE = 0 THEN Print('The folder is protected from deletion.\n')
  	
  	dir.close()
  ENDIF
  END dir

How to create or open a file:

  DEF file:PTR TO cFile
  
  NEW file.new()
  IF file.open('examplePortablePath.txt')
  	->use the file now
  	Print('The file size is \d bytes.\n', file.getSize() !!VALUE)
  	
  	file.close()
  ENDIF
  END file

How to read the contents of an opened file:

  DEF buffer:ARRAY OF BYTE, size
  
  size := file.getSize() !!VALUE
  NEW buffer[size+1]
  file.setPosition(0)
  file.read(buffer, size)
  
  buffer[size] := 0		->make it a valid string
  Print('The file contents:\n')
  Print('\s\n', buffer)
  
  END buffer

How to add an immediate string to the end of an opened file:

  file.setPosition(-1)
  file.write('Hello world!\n', STRLEN)

How to add a variable string to the end of an opened file:

  DEF myString:ARRAY OF CHAR
  
  myString := 'Hello world!\n'
  file.setPosition(-1)
  file.write(myString, StrLen(myString))

How to list the contents of an opened directory:

  DEF list:PTR TO cDirEntryList
  
  Print('The folder "\s" contains:\n', dir.getName())
  list := dir.makeEntryList()
  IF list.gotoFirst()
  	REPEAT
  		Print('* \s\n', list.infoName())
  	UNTIL list.gotoNext() = FALSE
  ENDIF
  
  END list

How to check a file or directory exists:

  IF ExistsPath('portablePath')
  	Print('It exists!\n')
  ENDIF

How to delete a file or (empty) directory:

  IF DeletePath('portablePath') = FALSE
  	Print('Failed to delete it!\n')
  ENDIF

How to turn a portable path back into a host OS path the user will expect:

  DEF hostPath:STRING
  
  hostPath := ExportPath('portable/path/of/some file or directory')
  Print('The host OS path is "\s".\n', hostPath)
  
  END hostPath

The following example programs use it:

  Examples/std/Shell/AmigaAttributes.e
  Examples/std/Shell/BinDif.e
  Examples/std/Shell/DeleteModuleCache.e
  Examples/std/Shell/PEGCC.e
  Examples/std/Shell/RecursiveDir.e
  Examples/std/Shell/ToyInterpreter/ToyInterpreter.e

Released programs which are known to use it:

  FolderSync2     ( cshandley.co.uk )
  AmigaAttributes ( cshandley.co.uk )
  
  PictureAlbum    ( cshandley.co.uk )
  Age of Thieves  ( os4depot.net/?function=showfile&file=game/board/age_of_thieves.lha )
  Ami-Ingenious   ( os4depot.net/?function=showfile&file=game/board/ami-ingenious.lha )
  FlowerWay       ( os4depot.net/?function=showfile&file=game/puzzle/flowerway.lha )
  HueFlow         ( os4depot.net/?function=showfile&file=game/puzzle/hueflow.lha )
  Ami-Scratch     ( os4depot.net/?function=showfile&file=graphics/misc/amiscratch.lha )
  Ami-Bootguard   ( os4depot.net/?function=showfile&file=utility/misc/ami-bootguard.lha )
  Ami-Lineapolis  ( www.lineapolis.dizzy.pl )

26.2. Some common terms

So that you can more easily understand the procedures & methods, here are a few common terms:

26.3. Procedures (of cPath)

All of these procedures can also be found in the smaller 'std/cPath_shared' module, with the exception of DeleteDirPath(), CreateDirs() & RecurseDir().

  PROC IsFile(path:ARRAY OF CHAR) RETURNS isFile:BOOL
  PROC IsDir( path:ARRAY OF CHAR) RETURNS  isDir:BOOL
  PROC FastIsFile(path:STRING) RETURNS isFile:BOOL
  PROC FastIsDir( path:STRING) RETURNS  isDir:BOOL
  PROC InvalidFilePath(filePath:ARRAY OF CHAR) RETURNS invalid:BOOL
  PROC InvalidFileName(fileName:ARRAY OF CHAR) RETURNS invalid:BOOL
  PROC InvalidDirPath(  dirPath:ARRAY OF CHAR) RETURNS invalid:BOOL
  PROC InvalidDirName(  dirName:ARRAY OF CHAR) RETURNS invalid:BOOL
  PROC StrCmpPath( path1:ARRAY OF CHAR, path2:ARRAY OF CHAR, len=ALL, firstOffset=0, secondOffset=0) RETURNS match:BOOL
  PROC OstrCmpPath(path1:ARRAY OF CHAR, path2:ARRAY OF CHAR, max=ALL, firstOffset=0, secondOffset=0) RETURNS sign:RANGE -1 TO 1

IsFile() & IsDir() check whether the given path is for a file or dir, by checking whether it ends in a slash or not. Since a dir always ends in a slash, this is completely reliable.

FastIsFile() & FastIsDir() are faster versions of IsFile() & IsDir(), but they require that the given path is an e-string.

InvalidFilePath(), InvalidFileName(), InvalidDirPath() & InvalidDirName() check whether the given path/name conforms to basic validity rules, such as ending with a slash or not.

StrCmpPath() is like StrCmp() & StrCmpNoCase(), but with the case-sensitivity determined by the host OS. i.e. Case-sensitive for Linux, and case-insensitive for everything else.

OstrCmpPath() is like OstrCmp() & OstrCmpNoCase(), but with the case-sensitivity determined by the host OS.

  PROC FindName(      path:ARRAY OF CHAR) RETURNS       name:ARRAY OF CHAR, nameLength
  PROC ExtractName(   path:ARRAY OF CHAR) RETURNS       name:OWNS STRING
  PROC ExtractDevice( path:ARRAY OF CHAR) RETURNS devicePath:OWNS STRING
  PROC ExtractSubPath(path:ARRAY OF CHAR) RETURNS    subPath:OWNS STRING

FindName() finds the name in a (file or directory) path, and returns a name array that points to it. It also returns the name length as nameLength.

ExtractName() returns an e-string containing a copy of the name in a path.

ExtractDevice() returns an e-string containing a copy of the device in a path (which will end in a :/), or an empty e-string if there is no device.

ExtractSubPath() returns an e-string containing a copy of everything except the name in a path.

  PROC CurrentDirPath() RETURNS dirPath:OWNS STRING
  PROC ExistsPath(      path:ARRAY OF CHAR, fileOrDir=FALSE:BOOL) RETURNS exists:BOOL
  PROC RenamePath(  origPath:ARRAY OF CHAR, newPath:ARRAY OF CHAR, force=FALSE:BOOL) RETURNS success:BOOL
  PROC DeletePath(      path:ARRAY OF CHAR, force=FALSE:BOOL, fileOrDir=FALSE:BOOL) RETURNS success:BOOL
  PROC DeleteDirPath(dirPath:ARRAY OF CHAR, force=FALSE:BOOL) RETURNS success:BOOL
  PROC ImportDirPath(  hostDirPath:ARRAY OF CHAR) RETURNS  dirPath:OWNS STRING
  PROC ImportFilePath(hostFilePath:ARRAY OF CHAR) RETURNS filePath:OWNS STRING
  PROC ExportPath(path:ARRAY OF CHAR) RETURNS hostPath:OWNS STRING
  PROC ExpandPath(path:ARRAY OF CHAR) RETURNS expandedPath:OWNS STRING
  PROC MakeUniquePath(file1dir2, dirPath:ARRAY OF CHAR, base=NILA:ARRAY OF CHAR) RETURNS newPath:OWNS STRING

CurrentDirPath() returns the program's current directory as an e-string.

ExistsPath() returns whether the given file/dir exists. If fileOrDir is TRUE then it will ignore whether the given path is for a file or dir (since many filingsystems disallow files with the same names as directories).

RenamePath() attempts to rename the given file/dir, changing it from origPath to newPath, and returning whether it succeeded or not. It will fail if the file is read or write protected, unless force is used to tell it to temporarily unprotect the file/dir.

DeletePath() attempts to delete the given file/dir, returning whether it succeeded or not. It will fail if the directory is not empty. If force is TRUE then it will unprotect the file/dir before attempting to delete it. If fileOrDir is TRUE then it will ignore whether the given path is for a file or dir (since many filingsystems disallow files with the same names as directories).

DeleteDirPath() attempts to delete the given dir, and everything it contains, including all sub-directories, returning whether it completely succeeded or not. If force is TRUE then it will unprotect any dirs before attempting to delete them.

ImportFilePath() & ImportDirPath() converts a host OS file/directory path into the portable format, returning an e-string. If a NILA parameter is supplied, then NILS will be returned.

ExportPath() converts a portable path into the host OS file/directory format, returning an e-string. If a NILA parameter is supplied, then NILS will be returned.

ExpandPath() takes a portable path and makes it as full & unamiguous as possible. Thus it replaces any aliases or links or assignments with the actual physical path, and ensures that the path is not relative to the current directory. It returns an e-string.

MakeUniquePath() creates an e-string path that does not yet exist inside dirPath. For file1dir2, 1 returns a file path, while 2 returns a dir path. If base is not given then it will default to 'TMP'. The name of the created path (inside dirPath) will begin with base, if it is supplied.

  PROC ReadLink(  path:ARRAY OF CHAR) RETURNS targetPath:OWNS STRING, specific:QUAD
  PROC CreateLink(path:ARRAY OF CHAR, targetPath:ARRAY OF CHAR, specific:QUAD) RETURNS success:BOOL, unknown:BOOL
  PROC CreateDirs(path:ARRAY OF CHAR, ignoreName=FALSE:BOOL) RETURNS success:BOOL
  PROC RecurseDir(dirPath:ARRAY OF CHAR, funcFile:PTR TO funcRecurseFile, funcDir=NIL:PTR TO funcRecurseDir, funcDirFailure=NIL:PTR TO funcRecurseDirFailure, funcDirAbort=NIL:PTR TO funcRecurseDirAbort)

ReadLink() examines a link at path, returning the targetPath of the link & the specific type of the link. If path is not a link (or does not exist at all), then it returns NILS for targetPath & 0 for specific.

It's main benefit is that it allows getting the target of a soft link, when the target does not exist (and so cannot be opened using cFile).

CreateLink() creates a link from path to targetPath of the type given by specific. path must not exist, while targetPath should exist, otherwise it will return FALSE for success. It will return FALSE for unknown unless specific was not recognised.

This is much more efficient than creating an empty file with cFile/cDir, and then using changeExtra() to turn it into a link. As with changeExtra(), targetPath must be in the portable format.

CreateDirs() ensures that all the dirs of a given path exist, creating them if necessary, and returning whether it succeeded or not. If ignoreName is TRUE then the final file/dir at the end of the path is ignored.

RecurseDir() recursively scans the dirPath directory (and sub-directories), calling the supplied funcFile function on every file it finds. If the optional funcDir function is supplied, then it calls that on every sub-directory it finds, and only scans that directory if the function returns TRUE. If the optional funcDirFailure function is supplied, then it calls that when opening a directory for scanning fails, and continues with further scans if the function returns TRUE. All three functions are passed the path as a STRING, with funcDirFailure also being passed two strings explaining the failure's origin & reason. Note that directory scanning is performed breadth-first & in alphanumerical (sorted) order.

If a Ctrl-C is received then scanning is halted. By default it will then raise a "BRK" exception, but if the optional funcDirAbort function is supplied, then it calls that with the next directory that would have been scanned, and then RecurseDir() returns.

Thus skeleton functions look like this:

  FUNC yourFuncFile(filePath:STRING) OF funcRecurseFile
  ENDFUNC
  
  FUNC yourFuncDir(dirPath:STRING) OF funcRecurseDir RETURNS scanDir:BOOL
     scanDir := TRUE
  ENDFUNC
  
  FUNC yourFuncDirFailure(dirPath:STRING, failureOrigin=NILA:ARRAY OF CHAR, failureReason=NILA:ARRAY OF CHAR) OF funcRecurseDirFailure RETURNS continueScan:BOOL
     continueScan := TRUE
  ENDFUNC
  FUNC yourFuncDirAbort(nextDirPath:STRING) OF funcRecurseDirAbort
     Raise("BRK")
  ENDFUNC

And RecurseDir() would use them like this:

  RecurseDir('your dir', yourFuncFile, yourFuncDir, yourFuncDirFailure, yourFuncDirAbort)

But if you are feeling particularly clever, then you can combine the first two directory functions into one, whose skeleton looks like this:

  FUNC yourFuncDir2(dirPath:STRING, failureOrigin=NILA:ARRAY OF CHAR, failureReason=NILA:ARRAY OF CHAR) OF funcRecurseDirFailure RETURNS doScan:BOOL
     IF failureOrigin
        doScan := TRUE      ->equivalent to continueScan := TRUE
     ELSE
        doScan := TRUE      ->equivalent to scanDir := TRUE
     ENDIF
  ENDFUNC

And you would use it like this:

  RecurseDir('your dir', yourFuncFile, yourFuncDir2, yourFuncDir2)

Alternatively, another clever thing you can do is combine the file & first directory functions into one, whose skeleton looks like this:

FUNC yourFuncFileDir(path:STRING) OF funcRecurseDir RETURNS scanDir:BOOL

	IF FastIsFile(path)
		->do file stuff
	ELSE
		->do dir stuff
		scanDir := TRUE
	ENDIF
ENDFUNC

And you would use it like this:

  RecurseDir('your dir', yourFuncFileDir, yourFuncFileDir, yourFuncDirFailure)

You could even combine this function with the funcDirFailure directory function, in a similar fashion to before, which is left as an exercise for the reader.


Note that the funcRecurseDirAbort function must always be implemented separately.

26.4. Methods of cPath

This (abstract) class is the parent of both the cFile & cDir classes, so that both files & directories share many methods. This mean that not only are there less methods for you to learn, but it also allows you to treat files & directories in a similar way.

(And advanced users can write procedures which take a cPath (instead of a cFile or cDir), so that they will work on both files & directories.)

So please keep in mind that the following methods apply to both files & directories!

The cPath class can also be found in the smaller 'std/cPath_shared' module.

  /* Methods of cPath, which inherits cExtra */
  METHOD open(path:ARRAY OF CHAR, readOnly=FALSE:BOOL, forceOpen=FALSE:BOOL) RETURNS success:BOOL
  METHOD create(path:ARRAY OF CHAR, doNotReplace=FALSE:BOOL, forceOpen=FALSE:BOOL) RETURNS success:BOOL
  METHOD close()
  METHOD flush()
  METHOD sleep()
  METHOD clone(writeNotRead=FALSE:BOOL) RETURNS clone:OWNS PTR TO cPath
  METHOD infoFailureReason() RETURNS reason:ARRAY OF CHAR
  METHOD infoFailureOrigin() RETURNS origin:ARRAY OF CHAR
  METHOD infoReadOnly() RETURNS readOnly:BOOL
  METHOD infoIsOpen() RETURNS isOpen:BOOL

open() must be used before any other method. And if you wish to use any setX() methods, then readOnly must be FALSE. If forceOpen is TRUE then it will *temporarily* clear any read or write protection, so that the file can be opened. Be sure to check that TRUE is returned for success, and if it isn't then you can use infoFailureReason()/etc just like for any other method that fails.

create() is an alternative to open, which ensures that an empty file/dir is created. If the file/dir already exists then normally it will delete that file/dir, but if doNotReplace is TRUE then it will just fail (returning FALSE).

close() must be used when you are finished with the file/dir, and before you use open() again. In read-write mode, all cached changes are comitted to disk.

flush() forces the cache to be emptied. In read-only mode the cache will be refreshed with current information, while in read-write mode all cached changes will be comitted to disk.

sleep() indicates you won't be accessing this file/dir for some time, and so it is OK to free any major resources (typically the file read/write cache), which MAY require flushing some caches. This allows you to have lots of files open, without wasting much memory on file caches.

clone() creates another object with the same file/dir open, but in read-only mode unless writeNotRead is TRUE. If it fails to open the file/dir, then it will return NIL.

infoFailureReason() & infoFailureOrigin() return strings that describe the reason for the last failure & the method in which the failure originated. No return codes are provided, because these would be inherantly non-portable.

infoReadOnly() returns the readOnly value that open() was supplied with.

infoIsOpen() returns whether anything is currently open.

  /* more methods of cPath */
  METHOD setAttributes(attr, mask=-1) RETURNS success:BOOL
  METHOD getAttributes()              RETURNS attr
  METHOD getAttributesSupported()     RETURNS mask
  METHOD setPath(path:ARRAY OF CHAR)    RETURNS success:BOOL
  METHOD getPath()                      RETURNS path:ARRAY OF CHAR
  METHOD setSubPath(path:ARRAY OF CHAR) RETURNS success:BOOL
  METHOD getSubPath()                   RETURNS path:OWNS STRING
  METHOD setName(name:ARRAY OF CHAR)    RETURNS success:BOOL
  METHOD getName()                      RETURNS name:ARRAY OF CHAR
  ->plus methods inherited from cExtra

For the inherited methods read 26.8. Methods of cExtra.

setAttributes() changes the attributes (flags) to attr, but only affects the attributes given by mask. The available attribute are:

  CPA_STRICT, CPA_READ, CPA_WRITE, CPA_DELETE, CPA_HIDE,
  CPA_UNUSED1, CPA_UNUSED2, CPA_UNUSED3, CPA_UNUSED4

Note that CPA_STRICT affects how the other attributes are interpreted, for example: The FAT filing system combines the meaning of CPA_WRITE & CPA_DELETE into one flag. Without CPA_STRICT you must clear both CPA_WRITE & CPA_DELETE before either of them is cleared. But with CPA_STRICT you only need to clear either of CPA_WRITE or CPA_DELETE before both are cleared.

getAttributes() returns the current attributes, such as CPA_READ. Note that CPA_STRICT has no meaning here.

getAttributesSupported() returns a mask indicating which attributes are supported by the current host OS.

setPath() & getPath() allow you to change & retrieve the complete path (subpath & name) of the current file/dir as an e-string.

setSubPath() & getSubPath() allow you to change & retrieve the subpath of the current file/dir. Changing the subpath is equivalent to moving it. BEWARE that getSubPath() returns a new string, which you must END when you are finished with it.

setName() & getName() allow you to change & retrieve the name of the current file/dir. Changing the name is equivalent to renaming it.

26.5. Methods of cFile

This class is for handling files. You must create an object (using the new() method), after which you can open() & close() files as many times as you want.

The cFile class can also be found in the smaller 'std/cPath_File' module.

  /* Methods of cFile, which inherits cPath */
  METHOD new(padByte=0:BYTE)
  METHOD open(filePath:ARRAY OF CHAR, readOnly=FALSE:BOOL, forceOpen=FALSE:BOOL, atPastEndNotStart=FALSE:BOOL) RETURNS success:BOOL
  METHOD read( buffer:ARRAY, lengthInBytes, offsetInBytes=0, toByte=-1:INT)           RETURNS nextPos:BIGVALUE, numOfPadBytes
  METHOD write(buffer:ARRAY, lengthInBytes, offsetInBytes=0, noAutoExtend=FALSE:BOOL) RETURNS nextPos:BIGVALUE, numOfLostBytes
  METHOD infoPadByte() RETURNS padByte:BYTE

new() is the object's constructor. You can specify a pad byte other than 0 here.

open() has the additional atPastEndNotStart parameter. Normally the read/write position is at the start of a file, but if atPastEndNotStart is TRUE then it will be just past the end of the file.

read() reads lengthInBytes bytes into the buffer from the current read/write position. The current position is not changed by this method, so you must use the setPosition() method to change it. Luckily it returns the next sequential position, nextPos, should you need it.

offsetInBytes is an offset into the buffer (to avoid pointer arithmetic). Pad bytes will appear if you read after the end of the file. If toByte is given then it will not read past the occurance of the first toByte byte, with the remainder of the buffer being filled with pad bytes. If you read past the end of the file, then the buffer will similarly be filled with pad bytes.

write() writes lengthInBytes bytes from the buffer to the current read/write position. The current position is not changed by this method, so you must use the setPosition() method to change it. Luckily it returns the next sequential position, nextPos, should you need it.

offsetInBytes is an offset into the buffer (to avoid pointer arithmetic). Normally writing past the end of a file will cause it's size to grow as needed, but if noAutoExtend is TRUE then the file will NOT grow any larger (in which case numOfLostBytes will indicate how many bytes were not written). If you start writing beyond the end of a file, then any gap between the end of the file & your start position will be filled with pad bytes.

infoPadByte() returns the padByte value that new() was supplied with.

  /* more methods of cFile */
  METHOD setPosition(pos:BIGVALUE)
  METHOD getPosition(fromEnd=FALSE:BOOL) RETURNS pos:BIGVALUE
  METHOD setSize(sizeInBytes:BIGVALUE)
  METHOD getSize() RETURNS sizeInBytes:BIGVALUE
  METHOD setTime(time:BIGVALUE) RETURNS success:BOOL
  METHOD getTime()              RETURNS time:BIGVALUE
  METHOD makeCopy(path:ARRAY OF CHAR) RETURNS copy:OWNS PTR TO cFile
  ->plus methods inherited from cPath

For the inherited methods read 26.4. Methods of cPath.

setPosition() changes the current read/write position. You may go beyond the end of the file without changing the file's size. A negative pos indicates position from the end of the file (-1=after last byte, -2=last byte, etc). Note that an error will be raised if you attempt to go before the beginning of the file.

Positions are BIGVALUEs (which are typically 64-bit), although the host OS may not support positions which exceed 32-bits. (In fact no cFile implementation yet supports 64-bit values, but this will hopefully change.)

getPosition() retrieves the current read/write postion. If fromEnd is TRUE then it returns a negative position as measured from the end of the file (see setPosition()).

setSize() & getSize() allow you to change & retrieve the file's current size in bytes.

setTime() & getTime() allow you to change & retrieve the file's current time.

makeCopy() creates a precise copy of a file, including cExtra information, returning a file opened in write mode. It will not overwrite an existing file. It will return NIL if an error occured.

26.6. Methods of cDir

This class is for handling directories. You must create an object (using the new() method), after which you can open() & close() directories as many times as you want.

The cDir class can also be found in the smaller 'std/cPath_Dir' module.

  /* Methods of cDir, which inherits cPath */
  METHOD new()
  METHOD openParent(forceOpen=FALSE:BOOL) RETURNS success:BOOL
  METHOD openChild(relativePath:ARRAY OF CHAR, forceOpen=FALSE:BOOL) RETURNS success:BOOL
  METHOD makeEntryList() RETURNS list:OWNS PTR TO cDirEntryList
  ->plus methods inherited from cPath

For the inherited methods read 26.4. Methods of cPath.

new() is the object's constructor.

openParent() closes the current dir & opens the parent dir. If it fails then it will return FALSE for success & leave the original dir open. forceOpen has the same meaning as it does for the open() method.

openChild() closes the current dir & opens the given sub-dir, which must be a dirpath relative to the current dir. If it fails then it will return FALSE for success & leave the original dir open. forceOpen has the same meaning as it does for the open() method.

makeEntryList() returns a cDirEntryList object containing the result of a scan of the current directory.

26.7. Methods of cDirEntryList

This class is a sorted list containing the result of a directory scan. You can also do various things with it, such as combining two lists, and generating a "unique name" which is not present in the list.

The cDirEntryList class can also be found in the smaller 'std/cPath_Dir' module.

  /* Methods of cDirEntryList */
  METHOD clone() RETURNS clone:OWNS PTR TO cDirEntryList
  METHOD gotoFirst(any0file1dir2=0) RETURNS exists:BOOL
  METHOD gotoNext( any0file1dir2=0) RETURNS exists:BOOL
  METHOD infoName() RETURNS path:ARRAY OF CHAR
  METHOD findName(name:ARRAY OF CHAR, fileOrDir=FALSE:BOOL) RETURNS success:BOOL

clone() allows you to create an exact copy of the current object.

gotoFirst() changes the current position in the list to the first item. If any0file1dir2 is 1 then it goes to the first file in the list, while if it is 2 then it goes to the first directory in the list. Returns whether the requested item exists, with FALSE implying that the list is empty.

gotoNext() changes the current position in the list to the next item. If any0file1dir2 is 1 then it goes to the next file in the list, while if it is 2 then it goes to the next directory in the list. Returns whether the requested item exists, with FALSE implying that the end of the list has been reached.

infoName() returns the name of the current item.

findName() searches from the start of the list for the given name, returning whether it succeeded in finding a match. If fileOrDir is TRUE then it will ignore whether the given name is for a file or dir. If TRUE is returned for success then the current position is the matched item.

  /* more methods of cDirEntryList */
  METHOD remove() nextExists:BOOL
  METHOD add(name:ARRAY OF CHAR, toStartOfList=FALSE:BOOL) RETURNS success:BOOL
  METHOD addString(name:OWNS STRING, toStartOfList=FALSE:BOOL) RETURNS success:BOOL
  METHOD addList(list:PTR TO cDirEntryList) RETURNS numOfSameEntries
  METHOD sort(doNotCheckForDuplicates=FALSE:BOOL) RETURNS numOfSameEntries
  METHOD makeUniqueName(file1dir2, base=NILA:ARRAY OF CHAR) RETURNS name:OWNS STRING

remove() destroys the current item, moving to the next one. Returns whether there was a next item, with FALSE implying that the end of the list has been reached.

add() creates an item with the given name, and add's it to the list such that it stays sorted. Returns FALSE if there was already an item with that name, since duplicates are not allowed.

(If toStartOfList=TRUE then the item is simply added to the start of the list, in which case the list is NOT sorted, and no check for duplicates is made. This state is NOT ALLOWED, except temporarily, so once you are finished adding items you MUST call the sort() method. This feature is useful for both speed, and so that you can easily modify a whole list without processing any item more than once (modify an item by removing the old item & adding the new 'modified' item).)

addString() works like add(), but it uses the provided e-string for speed. The list will now handle deallocation of the e-string, so you must NOT deallocate it yourself. If it returns FALSE, then the e-string will be deallocated immediately.

addList() creates copies of all items in the provided list, and adds them to the current list. It returns the number of duplicates that were not added.

sort() ensures the list is sorted, returning the number of duplicates which were found & removed. If you know for sure that no duplicates are present, then you can speed it up by using doNotCheckForDuplicates=TRUE.

makeUniqueName() creates an e-string name that does not yet exist in the list. For file1dir2, supply 1 for a file path, or 2 for a dir path. If base is not given then it will default to 'TMP'. The created name will begin with base.

26.8. Methods of cExtra

This class is used for all the host OS information which is not accessible by normal means. In the Amiga's case this means file comments & certain flags.

You must specify what item of information you want to read or change, using a specific:QUAD value. The supported values depend on the host OS. For example:

Take care using them, because they are not completely portable!

The cExtra class can also be found in the smaller 'std/cPath_shared' module.

  /* Methods of cExtra */
  METHOD setExtra(extra:PTR TO cExtra) RETURNS success:BOOL
  METHOD getExtra()                    RETURNS extra:OWNS PTR TO cExtra
  METHOD changeExtra(specific:QUAD, value) RETURNS success:BOOL, unknown:BOOL
  METHOD queryExtra( specific:QUAD)        RETURNS value, unknown:BOOL

setExtra() makes the object have the same information as that stored by extra (which could be a cFile or cDir object). Returns FALSE if it could not set all of the information.

getExtra() returns a new cExtra object, which contains a copy of all the current object's cExtra information.

changeExtra() changes a particular piece of information (given by specific) in the object to the supplied value. Returns whether it succeeded or not, and if it failed then whether that failure was due to specific being unknown.

queryExtra() returns a particular piece of information (given by specific) in value. This will be 0 when specific is unknown, but for cases where this is a valid value you need to check unknown.

26.9. The portable path format

Portable paths are represented in the same format, whatever OS is being used. This means that manipulation of path strings is portable (and also quite easy). You must use ImportFilePath(), ImportDirPath() & ExportPath() to convert between the OS format & the portable format.

Here are a some examples of valid paths:

  device:/subpath/filename
  device:/subpath/dirname/
  subpath/filename

On Linux absolute paths must always start with a colon, unless it references another mount point:

  :/tmp/tempfile
  :/root/.bashrc
  /media/drivename:/folder/file

26.10. Date & time

Date & time is measured as the number of seconds since 0:00:00 (midnight) on 1st January 2000. Dates before that are negative! Values are BIGVALUEs, which are typically 64-bit, but may be 32-bit for some targets (such as AmigaE).

26.11. Exceptions

Here is a list of exceptions that are used:

  exception   exceptionInfo   Reason
  "FULL"      (description)   Error due to disk being full (no space); file left in previous state.
  "FILE"      (description)   Error due to a serious filing system failure.
  "BRK"       (description)   Received a break signal (Ctrl-C) during a lengthy operation.
  
  "EMU"       (description)   Error from Method Use (an inappropriate argument or use).
  "EPU"       (description)   Error from Procedure Use (an inappropriate argument or use).
  "BUG"       (description)   Error due to a bug being detected.
  "MEM"       NILA            Error due to a lack of memory.

26.12. Assignments on Windows & Linux

Windows & Linux do not support assignments (beyond single drive letters in Windows' case), so there is support for 'faking' them, which only works for programs compiled by Portabl E. The assigments are stored in one or more text files, in the following locations on Windows:

  %USERPROFILE%\Assignments.txt
  C:\PortablE\Assignments.txt
  C:\Assignments.txt

And these on Linux:

  $HOME/.portable/Assignments.txt
  /root/.portable/Assignments.txt

In case case on conflicting assignments in different files, the first file takes priority (as it is read last & overwrites any previous assignments).

Portabl E has the HOME: assignment built-in, which points to the user's home folder, and can even be used in the Assignments.txt files themselves.

As standard Portabl E requires the PEmodules: assignment, which would look something like this in the Assignments.txt file on Windows:

  PEmodules:  C:/PortablE/PEmodules

And like this on Linux:

  PEmodules:  HOME:/.portable/PEmodules

Each assignment is on a single line, with the assignment name ending in a colon, followed by some tabs or spaces, and then the target path (which must be absolute not relative). The target path must not have any spaces after it, as they will be treated as part of the path. Note that the target path can use previously declared assignments, as well as Windows network paths. Nonsensical lines will simply be ignored.

Here's an example Assignments.txt file for Windows:

  Code:      HOME:\Documents\Code
  PEmodules: Code:\PEmodules

And for Linux:

  Code:      HOME:/Code
  PEmodules: Code:/PEmodules

26.13. Advanced details

Various technical details have been overlooked so far, but you may find it useful to know some of them:

Go back to CONTENTS


27. MODULE 'std/cSnd'

This module provides a easy way of playing sounds, which is suitable for games & multimedia.

Supported OSes: AmigaOS4, AmigaOS3, AROS, MorphOS.

27.1. Example usage

How to play a sound:

  DEF snd:PTR TO cSnd
  
  CreateApp().build()		->you only need to do this once!
  snd := LoadSound('MySound.wav')
  snd.play()

How to wait for a sound to finish playing:

  snd.waitForPlayToFinish()

A more flexible way to wait for a sound to finish playing:

  WHILE WaitForSoundEvent() <> snd DO EMPTY

Here's another way to play a sound:

  CreateApp().build()		->you only need to do this once!
  StoreSound('test', 0, LoadSound('MySound.wav'))
  UseSound('test', 0).play()

The following example programs use it:

  Examples/std/Multimedia/ShootEmUp/ShootEmUp.e

Released programs which are known to use it:

  Ami-Ingenious ( os4depot.net/?function=showfile&file=game/board/ami-ingenious.lha )

27.2. Procedures

  PROC    LoadSound(file:ARRAY OF CHAR, allowReturnNIL=FALSE:BOOL) RETURNS sound:PTR TO cSnd
  PROC DestroySound(sound:PTR TO cSnd) RETURNS nil:PTR TO cSnd
  PROC  WaitForSoundEvent() RETURNS sound:PTR TO cSnd
  PROC CheckForSoundEvent() RETURNS sound:PTR TO cSnd
  PROC StoreSound(name:ARRAY OF CHAR, number, sound:PTR TO cSnd) RETURNS storedSound:PTR TO cSnd
  PROC   UseSound(name:ARRAY OF CHAR, number, allowReturnNIL=FALSE:BOOL) RETURNS sound:PTR TO cSnd

LoadSound() loads the given sound, and returns a cSnd object for it. The file path must be given in the portable format used by the cPath module, so you may need to use it's ImportFilePath() procedure first. If the file could not be loaded, then an exception will be raised (unless TRUE was given to allowReturnNIL, in which case NIL would be returned instead).

DestroySound() destroys the supplied sound object. Your sounds will be automatically destroyed when your program quits, so you may not need to use this! You may pass it a NIL parameter without any problem. It returns NIL for your convenience.

WaitForSoundEvent() waits for any playing sound to stop (unless one has already stopped), and then returns that sound. Note that it will only remember the most recent events (typically the last 100), so ensure that you watch for events regularly.

CheckForSoundEvent() checks if any previously playing sound has stopped, and returns that sound. If no sound has stopped, then it returns NIL.

StoreSound() & UseSound() allow you to store & retrieve sounds using a name string, and optionally a number. The string must be an 'immediate string', not one you have created. It returns the stored sound, so you can use it straight away. Here's an example of how you might use it:

  StoreSound('explosion', 0, LoadSound('explosion.wav'))
  
  UseSound('explosion', 0).play()

If you try to store more than one sound with the same name & number combination, then an exception will be raised. This is to prevent you accidentally reusing them. And if you try to use a non-existant sound, then an exception will be raised; unless you gave TRUE for allowReturnNIL, in which case NIL will be returned.

27.3. Methods of cSnd

The cSnd class is a sound which can be played. Not only can you play several different sounds (from different objects) at the same time, but you can also play the same sound (from one object) several times.

For example, you can have a "shoot" sound, and play it every time the player shoots. If he fires quickly enough, then several "shoot" sounds can be playing at once.

  /* Methods of cSnd */
  METHOD play(playCount=1, speed=100)
  METHOD stop()
  METHOD infoLength()    RETURNS milliSeconds
  METHOD infoIsPlaying() RETURNS isPlaying:BOOL
  METHOD waitForPlayToFinish()
  METHOD setVolume(volume) RETURNS sound:PTR TO cSnd
  METHOD getVolume() RETURNS volume
  METHOD setPan(pan) RETURNS sound:PTR TO cSnd
  METHOD getPan() RETURNS pan

play() starts playing the sound, using the given parameters. playCount indicates how many times the sound should be played (back to back). Use 0 if you want the sound to play forever. speed allows you to change how fast the sound is played, where 100 is normal speed, 200 is double speed, 50 is half speed, and so on.

stop() stops the sound from playing (even if playing multiple times).

infoLength() returns the length of the sound in milliseconds.

infoIsPlaying() returns whether or not the sound is currently playing.

waitForPlayToFinish() pauses until the sound has stopped playing (completely).

setVolume() & getVolume() allow you to change & retrieve volume. This is how loud the sound will be played, where 100 is maximum volume, 50 is half volume, 0 is silent, and so on. It is used by subsequent play() calls.

setPan() & getPan() allow you to change & retrieve the pan. Pan allows the sound to be forced to come more from one speaker than the other, where -100 is entirely from the left speaker, 100 is entirely from the right speaker, 0 is evenly from both speakers, and so on. It will be used by subsequent play() calls.