MIDletPascal language reference

MIDletPascal

A small Pascal for the phones of the 2000s, the ones with a keypad, a screen 176 pixels wide and Java ME. A program compiles to a MIDlet: a JAR that runs on such a phone, in J2ME Loader, or in the emulator built into ANPASIDE.

This page describes the language as the mp3cc compiler accepts it, routine by routine. Where the original manual says otherwise, the compiler is what is described here.

program hello;
begin
  SetColor(255, 0, 0);
  DrawText('Hello world', 10, 10);
  Repaint;
  Delay(2000);
end.
A whole program: it writes a red line of text at 10, 10, shows it, and exits two seconds later.

1From source to a MIDlet

One run of mp3cc compiles one .pas file and writes class files, nothing else:

a programM.class, a subclass of the MIDP Canvas
a unita class named after the unit in lowercase, and a .bsf file with its symbols
a record typeR_0.class, R_1.class and so on

Because the program itself is the canvas, drawing and key handling are part of the language rather than a library. Everything else the compiler only names in its output: the units the program uses, the library classes it calls, and the runtime classes its built-in routines need. Compiling those units, collecting the classes and packing them into a JAR with a manifest is the job of the IDE. In ANPASIDE that is the Run button.

The runtime is a handful of small classes. FW.class goes into every JAR; the others only when a routine needs them, and the reference says which:

FSforms
F or Realreal numbers, see Real numbers
Ssome string, image and resource routines
RSrecord stores
HHTTP
Psound
SMSMS

Unlike other Pascals

  • A string is not an array of characters. Its first character is at index 0, and characters are read and changed with GetChar and SetChar; s[i] does not compile.
  • A function's result has to be used, as in standard Pascal; Turbo Pascal, Free Pascal and Delphi let a call stand on its own. FormAddString('Hi'); alone is error E432, so assign it: id := FormAddString('Hi');.
  • Parameters are always passed by value, and routines cannot be nested.
  • There are no sets, enumerated types, files, pointers or with.

2Program structure

A program is a header, declarations, and a main block:

program name;

  { constants, types, variables }
  { procedures and functions }

begin
  { statements }
end.

The program line may be left out. Declarations come in any order and any number of blocks. The program runs the main block and ends at its end., with the period.

As in every Pascal, keywords and names are case-insensitive: Begin, begin and BEGIN are one word.

Comments

{ braces }
(* parentheses and stars *)
// to the end of the line
/* C style */

Compiler directives such as {$R+} are read as ordinary comments: the kind of real numbers and of canvas is set by the build, not by the source.

3Data types

TypeHolds
integera 32-bit signed number, −2147483648 to 2147483647
reala number with a fraction, computed in software; see Real numbers
booleantrue or false
charone character; Ord and Chr convert it to and from its code
stringtext of any length, indexed from 0
imagea picture, from LoadImage or one of the ImageFrom functions
commanda soft-key command, from CreateCommand
recordStorean open record store
httpan HTTP connection
resourcea file from the JAR opened for reading

The last five are handles: a program passes them around but cannot look inside. From these, a program builds records and arrays.

Records

type hero = record
  x, y: integer;
  health: integer;
end;

var player, saved: hero;
begin
  player.x := player.x + 1;
  saved := player;          { copies every field }
end.

Assigning a record copies it, so changing saved later leaves player alone. A record cannot hold an array (error E446).

Each record type becomes a class numbered in the order the compiler meets it: R_0, R_1, and so on. The numbers start again with every run unless the build passes the next free one with -r, and ANPASIDE does, so that the record classes of two modules do not overwrite each other in the JAR. One case is still not covered: two units that use each other can end up with the same numbers, so keep record types out of such a pair. The compiler tells record types apart by their number alone, which is why a clash is not caught at compile time and shows up only as a crash on the phone.

Arrays

type board = array[1..8, 1..8] of integer;
var cells: board;
    scores: array[0..9] of integer;
begin
  cells[1, 1] := 0;
  scores[0] := 100;
end.

Each dimension has its own bounds, and there can be any number of dimensions. Arrays are not assigned whole, only element by element (error E443).

4Declarations

const
  minutesInHour = 60;
  greeting = 'To be or not to be';

type
  number = integer;
  point = record x, y: integer; end;

var
  index: integer;
  field: array[1..15] of integer;
  p: point;

begin
end.

const names a value, type names a type, and var declares variables, of a named type or one written out in place. Variables declared outside any routine are global: every procedure and function declared after them sees them.

5Statements

Where a statement has a body, one statement needs nothing around it and several go between begin and end.

Assignment

x := x + 1;

if

if lives = 0 then
  gameOver := true
else
begin
  lives := lives - 1;
  restart;
end;

for

for i := 1 to 10 do
  sum := sum + i;

for i := 10 downto 1 do
  DrawText(IntegerToString(i), 0, i * 10);

while and repeat

while GetKeyClicked = KE_NONE do
  Delay(100);

repeat
  Delay(100);
until GetKeyClicked <> KE_NONE;

repeat
  tick;
forever;

forever in place of until makes a loop that only break, exit or Halt ends. break leaves the innermost for, while or repeat, and is an error outside a loop.

case

case GetKeyClicked of
  KE_KEY2:          y := y - 1;
  KE_KEY8:          y := y + 1;
  KE_KEY4, KE_KEY6: x := x + key - KE_KEY5;   { several labels }
  KE_KEY5:          begin
                      DrawText('fire', 10, 10);
                      Repaint;
                    end;
  KE_STAR:          ;                         { does nothing }
  0..31:            Delay(50);                { a range, both ends included }
else
  x := 0;
  y := 0;
end;

case name of
  'left', 'l': dx := -1;
  'right':     dx := 1;
end;

The value tested is an integer, a char or a string. Labels are literals or constants, never variables; integer and char labels may also be ranges. The first matching arm runs and nothing falls through. The else part takes any number of statements and is optional; without it, a value that matches nothing does nothing.

  • String labels are compared exactly, upper and lower case included.
  • A label that repeats or overlaps another is error E465.
  • In an arm such as 1: if ok then go; else stop, the else after the semicolon belongs to the case, not to the if.
  • break in an arm leaves the loop around the case.

case needs mp3cc 3.5.4, which ANPASIDE ships since 2.5.0. Older compilers stop with E442.

6Procedures and functions

var total: integer;

procedure add(a: integer; b: string);
var len: integer;           { local, made anew on every call }
begin
  len := Length(b);
  total := a + len;
end;

function multiply(a, b: integer): integer;
begin
  multiply := a * b;
end;

function square(x: integer): integer;
begin
  result := x * x;
end;

begin
  add(multiply(2, 3), 'abc');
  total := square(total);
end.

A procedure returns nothing. A function returns the value last assigned to its own name, or to result. exit leaves a routine at once, and in the main block ends the program like Halt.

Parameters are passed by value. var in a parameter list is ignored with warning W436, so a routine cannot change its caller's variables, only globals. Routines cannot be declared inside other routines (error E431), but they can call themselves:

function factorial(n: integer): integer;
begin
  if n <= 1 then
    factorial := 1
  else
    factorial := n * factorial(n - 1);
end;

Two routines that call each other need one of them declared forward first:

procedure b(y: integer); forward;

procedure a(x: integer);
begin
  if x > 0 then b(x - 1);
end;

procedure b(y: integer);
begin
  if y > 0 then a(y - 1);
end;

7Units and libraries

A program can be split into units written in Pascal, and it can call Java through library classes. ANPASIDE also ships three libraries of its own.

Units

unit geometry;

interface
  function square(x: integer): integer;

implementation
  function square(x: integer): integer;
  begin
    square := x * x;
  end;

initialization
  { runs when the program starts }
end.
program game;
uses geometry;
var area: integer;
begin
  area := geometry.square(5);   { or square(5), unless two units share the name }
end.

A unit name has at least three characters; a shorter one is error E454, whose message says two. There is no finalization section.

A unit shares everything in its interface: constants, types, variables, procedures and functions. Its types, unlike the rest, are only found by their full name. With a unit shapes that declares type point = record x, y: integer; end, another module writes var p: shapes.point; a bare point is error E415, even for an alias such as type index = integer.

Libraries in Java

When a program needs something of MIDP that the language does not offer, it can be written in Java as a library class:

// Lib_mylib.java, compiled for CLDC 1.0 and preverified
public class Lib_mylib {
  public static int square(int value) {
    return value * value;
  }
}
program demo;
uses mylib;
var id: integer;
begin
  ShowForm;
  id := FormAddString('5 squared is ' + mylib.square(5));
  Delay(5000);
end.
  • The class has no package, and its name is Lib_ followed by the unit name in lowercase.
  • Only methods declared exactly public static are seen. One that is also final or synchronized is skipped without a word.
  • Parameters and results may be int, String, Image, Command, RecordStore or InputStream, and a method may return void.
  • A library has routines only, no types or variables.
  • The class goes in the project's library folder, libs/ in ANPASIDE, or in the compiler's global one. The project's folder is searched first.

For phone features such as vibration or the backlight, a library needs the Display; the original manual's chapter on advanced features shows how to reach it. A call that exists only in MIDP 2.0 belongs in a try/catch, or the MIDlet crashes on a MIDP 1.0 phone.

Libraries in ANPASIDE

ANPASIDE ships three libraries that a program reaches with uses and nothing to copy. A Lib_ class of the same name in the project's libs/ takes their place.

Touchseveral fingers at oncesince 2.5.2
Soundmusic and sound effects togethersince 2.6.0
Screenthe parts of the screen the camera and the corners coversince 2.6.0

Touch

For on-screen buttons held with several fingers, to walk and jump at the same time:

program buttons;
uses Touch;
var w, h, x, y, vy, floor: integer;
begin
  Touch.Init;
  w := GetWidth;
  h := GetHeight;
  floor := h - 120;
  x := w div 2;
  y := floor;
  vy := 0;
  repeat
    { each button follows its own finger }
    if touch_area(0, h - 80, 80, 80) > 0 then x := x - 4;
    if touch_area(90, h - 80, 80, 80) > 0 then x := x + 4;
    if (touch_area(w - 80, h - 80, 80, 80) > 0) and (y = floor) then vy := -15;

    y := y + vy;
    vy := vy + 1;
    if y >= floor then
    begin
      y := floor;
      vy := 0;
    end;

    SetColor(0, 0, 0);
    FillRect(0, 0, w, h);
    SetColor(255, 255, 255);
    FillRect(x, y - 40, 20, 40);
    DrawRect(0, h - 80, 80, 80);
    DrawRect(90, h - 80, 80, 80);
    DrawRect(w - 80, h - 80, 80, 80);
    Repaint;
    Delay(20);
  until false;
end.

Fingers are numbered 0 to 9. The first finger down is 0, and each next one takes the lowest free number. Touch also has every function of Lib_sensor, under the same names, following finger 0. A program moves over by writing uses Touch and Touch.Init where it had Sensor.

The touch_ functions see every finger and the pointer_ functions only finger 0, so they do not mix. A program that checks a rectangle with touch_area and then reads the position from pointer_pressed_x reads the wrong finger as soon as two are down. Take the position from the finger that is inside:

for i := 0 to 9 do
  if (touch_down(i) = 1) and (touch_x(i) >= x) and (touch_x(i) < x + w)
     and (touch_y(i) >= y) and (touch_y(i) < y + h) then
    slot := (touch_x(i) - x) div cell;

Following Nokia, J2ME Loader and ANPASIDE's runtime report more than one finger only to a JAR whose manifest has Nokia-UI-Enhancement: EnableMultiPointTouchEvents, and ANPASIDE adds it to every program that uses Touch. The fingers are told apart through Nokia's com.nokia.pointer.number property, so the JAR works in J2ME Loader too. On a phone without multi-touch every touch is finger 0, and Touch behaves like Lib_sensor.

All functions: Touch reference.

Sound

The built-in OpenPlayer has a single player, so background music stops for every effect. Sound has eight channels, 0 to 7. Each channel holds one sound and only ever replaces its own: music on one, effects on the others. It needs no initialization.

program game;
uses Sound;
var ok: integer;
begin
  ok := sound_open(0, '/music.mp3', 'audio/mpeg');
  ok := sound_open(1, '/shot.wav', 'audio/x-wav');
  sound_loop(0, -1);
  sound_volume(0, 60);
  ok := sound_play(0);
  repeat
    { the shot starts over at every press, the music plays on }
    if KeyToAction(GetKeyPressed) = GA_FIRE then ok := sound_play(1);
    Delay(20);
  until false;
end.

The loop count and the volume belong to the channel, not to the sound, so a music channel keeps its volume from one track to the next. OpenPlayer still works alongside, as one more sound.

In ANPASIDE's emulator and in exported APKs, Android plays every sound and mixes them, two MIDI files included. It takes MIDI, WAV, MP3, AAC and AMR. A type it does not know, such as audio/ogg, makes sound_open return 0. Whether an old phone mixes sounds at all is up to the phone; one that does not may return 0 from sound_play while another sound plays.

All functions: Sound reference.

Screen

ANPASIDE's emulator and the APKs it exports draw the canvas over the whole screen, under the camera cutout and into the rounded corners. Screen tells how far each of them reaches into the canvas, so that buttons and text stay clear while the game world still fills the screen:

program hud;
uses Screen;
var w, h, l, t, r, b: integer;
begin
  repeat
    w := GetWidth;
    h := GetHeight;
    l := screen_inset_left;
    t := screen_inset_top;
    r := screen_inset_right;
    b := screen_inset_bottom;

    SetColor(80, 160, 255);
    FillRect(0, 0, w, h);                     { the world, edge to edge }
    SetColor(255, 255, 255);
    DrawRect(w - r - 64, t, 64, 32);          { a menu button in the top right corner }
    DrawText('v 1.0', l, h - b - GetStringHeight('A'));
    Repaint;
    Delay(20);
  until false;
end.

The cutout counts as a band along its whole edge, as Android reports it. A rounded corner counts as the distance that brings the corner of a rectangle inside the curve, on both edges it touches. A Pixel 9 held sideways answers 173 on the camera side and 39 on the other three. The values change when the screen turns, so a game that rotates reads them again.

The runtime measures the screen and hands the values out as the system properties anpaside.screen.inset.left, .top, .right and .bottom. Only ANPASIDE answers them; in J2ME Loader and on an old phone every function returns 0, which is also correct there.

All functions: Screen reference.

8Operators

OperatorsMeaning
+ - * /arithmetic; on integers / is the same as div
div modinteger division and its remainder
= <> < > <= >=comparison; strings compare with upper and lower case distinct
and or xor notlogic on booleans, bitwise on integers
shl shr ushrshifts, also written << >> >>>; ushr fills with zeros, as Java's >>> does
+ on a stringjoins it with a string, char, integer, real or boolean

not binds tightest and the comparisons loosest, as in other Pascals, so (a > 0) and (b > 0) needs its parentheses.

Literals

255   $FF          { integers, decimal and hex }
3.14              { a real }
'it''s'           { a string; a doubled quote is a quote }
"it's"            { a string in double quotes }
#65   #$41        { the char 'A' by its code }

9Real numbers

CLDC 1.0, the Java ME of the early phones, has no floating point types, so real arithmetic is done in software. It is slow and makes the JAR bigger. The build, not the source, chooses one of two implementations:

Fixed pointFloating point
Switch-m1, the default-m2
ClassesF.classReal.class, Real$NumberFormat.class
Precisionlow, a fixed number of fractional bitsmuch higher
Costfast and smallslower, several KB more

All math functions but Abs and Sqr work on reals, as do StringToReal and the constant pi. In ANPASIDE the choice is the MathType line of the project's .aproj file.

10Beyond standard Pascal

MIDletPascal accepts a few things that standard Pascal does not:

  • exit and result in routines, as Delphi and Free Pascal have them;
  • forever to close a repeat loop;
  • ushr, also written >>>;
  • // and /* */ comments, and strings in double quotes;
  • raw JVM instructions in a bytecode … end block, with labels.

Most of them were added by Javier Santo Domingo for MIDletPascal 3. mp3cc is the 3.5 compiler ported to Linux and Android, and the port added one thing to the language: case, which 3.5 rejected with E442.

A build that only checks the compiler's messages can miss a failure: if the compiler process is killed, by a bad argument or a binary built for the wrong system, it writes no M.class and no error. A JAR holding nothing but FW.class is the sign. The exit code of mp3cc is its error count, so any other exit code means the process died. ANPASIDE checks both.

Built-in routines

The 159 routines every program can call without a uses clause, by area. Each signature is the one mp3cc accepts. The 4 routines marked not in mp3cc are listed in the original manual, but MIDletPascal 3.5, and so mp3cc, does not have them.

Drawing
DrawArc DrawEllipse DrawImage DrawLine DrawRect DrawRoundRect DrawText FillEllipse FillRect FillRoundRect GetColorBlue GetColorGreen GetColorRed GetColorsNum GetHeight GetImageHeight GetImageWidth GetStringHeight GetStringWidth GetWidth ImageFromBuffer ImageFromCanvas ImageFromImage IsColorDisplay LoadImage Plot Repaint SetClip SetColor SetDefaultFont SetFont
Keypad
GetKeyClicked GetKeyPressed KeyToAction
Date and time
Delay GetCurrentTime GetDay GetHour GetMinute GetMonth GetRelativeTimeMs GetSecond GetWeekDay GetYear GetYearDay
Math
Abs Acos Asin Atan Atan2 Cos Exp Frac Log Log10 Pow Rabs Sin Sqr Sqrt Tan ToDegrees ToRadians Trunc
Strings
Copy GetChar IntegerToString Length Locase Pos SetChar StringToInteger StringToReal Upcase
Forms and commands
AddCommand ChoiceAppendString ChoiceAppendStringImage ChoiceGetSelectedIndex ChoiceIsSelected ClearForm CreateCommand EmptyCommand FormAddChoice FormAddDateField FormAddGauge FormAddImage FormAddSpace FormAddString FormAddTextField FormGetDate FormGetText FormGetValue FormRemove FormSetDate FormSetText FormSetValue GetClickedCommand GetFormTitle GetTextBoxString MenuAppendString MenuAppendStringImage MenuGetSelectedIndex MenuIsSelected PlayAlertSound RemoveCommand RemoveFormTitle SetFormTitle SetTicker ShowAlert ShowCanvas ShowForm ShowMenu ShowTextBox
Record stores
AddRecordStoreEntry CloseRecordStore CloseRSEnumeration DeleteRecordStore DeleteRecordStoreEntry EnumerateRecords GetRecordStoreNextId GetRecordStoreSize ModifyRecordStoreEntry NextRecord OpenRecordStore ReadRecordStoreEntry UpdateRSEnumeration
HTTP
AddHttpBody AddHttpHeader CloseHttp GetHttpHeader GetHttpResponse IsHttpOpen OpenHttp SendHttpMessage SetHttpMethod
SMS
SmsIsSending SmsStartSend SmsWasSuccessfull
Sound
GetPlayerDuration OpenPlayer PlayTone SetPlayerCount StartPlayer StopPlayer
Resource files
CloseResource OpenResource ReadByte ReadLine ResourceAvailable
Other
Assert Chr Debug GetProperty Halt IsMidletPaused Odd Ord Random Randomize

Drawing

Everything is drawn into a buffer the size of the canvas, in the color set by SetColor, and Repaint shows it. The origin is the top left corner; x grows to the right and y down.

DrawArc

procedure DrawArc(x, y, width, height, startAngle, arcAngle: integer);

Draws the outline of an arc inside the rectangle at x, y. The arc begins at startAngle and runs arcAngle degrees counterclockwise. 0° points to three o'clock and 90° to twelve.

Example
begin
  DrawArc(0, 0, GetWidth, GetHeight, 0, 90);
  Repaint;
  Delay(1000);
end.

See also FillEllipse, DrawEllipse

DrawEllipse

procedure DrawEllipse(x, y, width, height: integer);

Draws the outline of the ellipse that fits the given rectangle.

Example
begin
  DrawEllipse(0, 0, GetWidth, GetHeight);
  Repaint;
  Delay(1000);
end.

See also FillEllipse

DrawImage

procedure DrawImage(img: image; x, y: integer);

Draws img with its top left corner at x, y.

Example
begin
  DrawImage(LoadImage('/logo.png'), 0, 0);
  Repaint;
  Delay(1000);
end.

See also LoadImage, GetImageWidth

DrawLine

procedure DrawLine(x1, y1, x2, y2: integer);

Draws a line from x1, y1 to x2, y2.

Example
begin
  DrawLine(10, 15, 25, 35);
  Repaint;
  Delay(1000);
end.

DrawRect

procedure DrawRect(x, y, width, height: integer);

Draws the outline of a rectangle.

See also FillRect

DrawRoundRect

procedure DrawRoundRect(x, y, width, height, arcWidth, arcHeight: integer);

Draws the outline of a rectangle with rounded corners. arcWidth and arcHeight are the size of the arc at each corner.

See also FillRoundRect

DrawText

procedure DrawText(text: string; x, y: integer);

Draws text in the current font and color, with the top left corner of its box at x, y.

Example
begin
  SetColor(255, 0, 0);
  DrawText('Hello world', 0, 0);
  Repaint;
  Delay(1000);
end.

See also SetFont, GetStringWidth

FillEllipse

procedure FillEllipse(x, y, width, height: integer);

Fills the ellipse that fits the given rectangle.

See also DrawEllipse

FillRect

procedure FillRect(x, y, width, height: integer);

Fills a rectangle with the current color. FillRect(0, 0, GetWidth, GetHeight) clears the screen.

See also DrawRect

FillRoundRect

procedure FillRoundRect(x, y, width, height, arcWidth, arcHeight: integer);

Fills a rectangle with rounded corners.

See also DrawRoundRect

GetColorBlue

function GetColorBlue: integer;

The blue part of the current color, 0 to 255.

See also SetColor

GetColorGreen

function GetColorGreen: integer;

The green part of the current color, 0 to 255.

See also SetColor

GetColorRed

function GetColorRed: integer;

The red part of the current color, 0 to 255.

See also SetColor

GetColorsNum

function GetColorsNum: integer;

How many colors the display can show. On a black-and-white screen this is the number of gray levels.

See also IsColorDisplay

GetHeight

function GetHeight: integer;

The height of the canvas in pixels.

See also GetWidth

GetImageWidth

function GetImageWidth(img: image): integer;

The width of img in pixels.

Example
var logo: image;
begin
  logo := LoadImage('/logo.png');
  { centered on the screen }
  DrawImage(logo, (GetWidth - GetImageWidth(logo)) div 2,
                  (GetHeight - GetImageHeight(logo)) div 2);
  Repaint;
  Delay(1000);
end.

See also GetImageHeight

GetStringHeight

function GetStringHeight(text: string): integer;

The height of text in pixels, in the current font.

Example
var text: string;
begin
  text := 'Text to display';
  DrawText(text, 0, (GetHeight - GetStringHeight(text)) div 2);
  Repaint;
  Delay(1000);
end.

See also GetStringWidth, SetFont

GetStringWidth

function GetStringWidth(text: string): integer;

The width of text in pixels, in the current font.

Example
var text: string;
begin
  text := 'Text to display';
  DrawText(text, (GetWidth - GetStringWidth(text)) div 2, 0);
  Repaint;
  Delay(1000);
end.

See also GetStringHeight, SetFont

GetWidth

function GetWidth: integer;

The width of the canvas in pixels.

See also GetHeight

ImageFromBuffer

function ImageFromBuffer(buffer: string; length: integer): image;

Decodes an image held in a string, for example one read from a resource or received over HTTP. Every phone takes PNG, some also JPEG. length is the number of bytes to decode. The original manual does not mention it.

Adds S.class to the JAR.

See also GetHttpResponse, ReadByte

ImageFromCanvas

function ImageFromCanvas(x, y, width, height: integer): image;

Copies a part of the canvas into a new image.

Adds S.class to the JAR.

See also ImageFromImage

ImageFromImage

function ImageFromImage(source: image; x, y, width, height: integer): image;

Copies a part of source into a new image. Useful for cutting frames out of a sprite sheet.

Adds S.class to the JAR.

See also ImageFromCanvas

IsColorDisplay

function IsColorDisplay: boolean;

true if the display shows colors, false if it only shows gray levels.

See also GetColorsNum

LoadImage

function LoadImage(name: string): image;

Loads a PNG from the JAR. The name starts with /: a file in the project's res/ folder is '/name.png'. If there is no such file the MIDlet stops.

Example
begin
  DrawImage(LoadImage('/icon.png'), 0, 0);
  Repaint;
  Delay(1000);
end.

See also DrawImage

Plot

procedure Plot(x, y: integer);

Sets one pixel to the current color.

Repaint

procedure Repaint;

Copies the drawing buffer to the screen. Drawing routines only change the buffer, so nothing is visible until Repaint. A repaint is slow on a phone: draw the whole frame first and call it once per frame.

Example
begin
  DrawText('Hello world', 0, 0);
  Repaint;
  Delay(1000);
end.

SetClip

procedure SetClip(x, y, width, height: integer);

Limits drawing to a rectangle: anything drawn outside it is dropped. SetClip(0, 0, GetWidth, GetHeight) lifts the limit.

Example
begin
  SetColor(0, 0, 0);
  FillEllipse(0, 0, GetWidth, GetHeight);
  Repaint;
  Delay(2000);

  SetClip(10, 10, 15, 25);      { only this part of the next ellipse is drawn }
  SetColor(255, 0, 0);
  FillEllipse(0, 0, GetWidth, GetHeight);
  Repaint;
  Delay(2000);
end.

SetColor

procedure SetColor(red, green, blue: integer);

Sets the color for everything drawn after it. Each part is 0 to 255: 0, 0, 0 is black, 255, 255, 255 white.

Example
begin
  SetColor(0, 0, 255);
  DrawText('Hello world', 0, 0);
  Repaint;
  Delay(1000);
end.

See also GetColorRed

SetFont

procedure SetFont(face, style, size: integer);

Sets the font for DrawText. The phone picks the closest font it has, and a phone with a single font ignores the call.

  • face: FONT_FACE_SYSTEM, FONT_FACE_MONOSPACE or FONT_FACE_PROPORTIONAL
  • style: FONT_STYLE_PLAIN, or any of FONT_STYLE_BOLD, FONT_STYLE_ITALIC and FONT_STYLE_UNDERLINED joined with or
  • size: FONT_SIZE_SMALL, FONT_SIZE_MEDIUM or FONT_SIZE_LARGE
Example
begin
  SetFont(FONT_FACE_SYSTEM, FONT_STYLE_BOLD or FONT_STYLE_UNDERLINED, FONT_SIZE_LARGE);
  DrawText('Hello world', 0, 0);
  Repaint;
  Delay(1000);
end.

See also SetDefaultFont, GetStringWidth

Keypad

Key codes for the number keys are the same on every phone. For the arrows and fire, go through KeyToAction; the raw codes are in key scan codes.

GetKeyClicked

function GetKeyClicked: integer;

The code of the last key pressed since the previous call, or KE_NONE. Reading it clears it, so a key press is reported once. The number keys, * and # have constants (KE_KEY0 to KE_KEY9, KE_STAR, KE_POUND); for the arrows and fire, use KeyToAction.

Example
begin
  repeat
    Delay(100);
  until GetKeyClicked = KE_STAR;
end.

See also GetKeyPressed, KeyToAction, Key scan codes

GetKeyPressed

function GetKeyPressed: integer;

The code of the key held down right now, or KE_NONE. Use it for movement that lasts as long as the key is held, and GetKeyClicked for single presses.

Example
begin
  repeat
    Delay(100);
  until GetKeyPressed = KE_STAR;
end.

See also GetKeyClicked, KeyToAction

KeyToAction

function KeyToAction(keyCode: integer): integer;

Turns a key code into a game action, which is the same on every phone: GA_UP, GA_DOWN, GA_LEFT, GA_RIGHT, GA_FIRE, GA_GAMEA to GA_GAMED, or GA_NONE. The raw codes of the arrow keys differ from maker to maker; see key scan codes.

Example
begin
  repeat
    Delay(100);
  until KeyToAction(GetKeyClicked) = GA_FIRE;
end.

See also GetKeyClicked, Predefined constants

Date and time

A time is an integer: seconds since midnight, 1 January 1970. GetCurrentTime gives the current one, and the other functions take it apart.

Delay

procedure Delay(ms: integer);

Waits ms milliseconds. A game loop calls it once per frame so that the phone has time for other work.

Example
begin
  DrawText('Hello world', 0, 0);
  Repaint;
  Delay(2000);
end.

GetCurrentTime

function GetCurrentTime: integer;

The current time as seconds since midnight, 1 January 1970. The other date functions take this number.

Example
var time: integer;
begin
  time := GetCurrentTime;
  DrawText('It is ' + GetHour(time) + ':' + GetMinute(time) + ':' + GetSecond(time), 0, 0);
  Repaint;
  Delay(1000);
end.

See also GetHour, GetDay

GetDay

function GetDay(time: integer): integer;

The day of the month of time, 1 to 31.

See also GetCurrentTime

GetRelativeTimeMs

function GetRelativeTimeMs: integer;

The system clock in milliseconds, cut to a 32-bit integer: good for timing, not for telling the date. It can be negative, and about every 50 days it jumps from the largest integer to the smallest. The difference of two readings, now - last, stays right across that jump.

Example
  { move the block down once a second, sideways at every key press }
  last := GetRelativeTimeMs;
  repeat
    key := KeyToAction(GetKeyClicked);
    if key = GA_LEFT then moveLeft;
    if key = GA_RIGHT then moveRight;
    now := GetRelativeTimeMs;
    if now - last > 1000 then
    begin
      last := now;
      moveDown;
    end;
    Delay(20);
  until gameOver;

See also Delay

GetWeekDay

function GetWeekDay(time: integer): integer;

The day of the week of time: 1 is Sunday, 2 Monday, and 7 Saturday.

See also GetCurrentTime

GetYearDay

function GetYearDay(time: integer): integer;

The day of the year of time, 1 to 366.

See also GetCurrentTime

Math

Angles are in radians. Apart from Abs and Sqr, these work on reals.

Abs

function Abs(n: integer): integer;

The absolute value of an integer.

See also Rabs

Acos

function Acos(x: real): real;

The arc cosine of x, in radians, 0 to π.

Adds F.class to the JAR, or Real.class with -m2.

Asin

function Asin(x: real): real;

The arc sine of x, in radians, −π/2 to π/2.

Adds F.class to the JAR, or Real.class with -m2.

Atan

function Atan(x: real): real;

The arc tangent of x, in radians, −π/2 to π/2.

Adds F.class to the JAR, or Real.class with -m2.

See also Atan2

Atan2

function Atan2(y, x: real): real;

The angle of the point x, y seen from the origin, in radians, −π to π. Unlike Atan(y / x) it knows which quarter the point is in and accepts x = 0.

Adds F.class to the JAR, or Real.class with -m2.

See also Atan

Cos

function Cos(x: real): real;

The cosine of an angle in radians.

Adds F.class to the JAR, or Real.class with -m2.

See also ToRadians

Exp

function Exp(x: real): real;

e raised to the power x.

Adds F.class to the JAR, or Real.class with -m2.

See also Log

Frac

function Frac(x: real): real;

The fractional part of x: Frac(1.25) is 0.25.

Adds F.class to the JAR, or Real.class with -m2.

See also Trunc

Log

function Log(x: real): real;

The natural logarithm of x.

Adds F.class to the JAR, or Real.class with -m2.

See also Log10, Exp

Log10

function Log10(x: real): real;

The base 10 logarithm of x.

Adds F.class to the JAR, or Real.class with -m2.

See also Log

Pow

function Pow(a, b: real): real;

a raised to the power b.

Adds F.class to the JAR, or Real.class with -m2.

Rabs

function Rabs(x: real): real;

The absolute value of a real.

Adds F.class to the JAR, or Real.class with -m2.

See also Abs

Sin

function Sin(x: real): real;

The sine of an angle in radians.

Adds F.class to the JAR, or Real.class with -m2.

See also ToRadians

Sqr

function Sqr(n: integer): integer;

The square of an integer, n * n.

See also Sqrt

Sqrt

function Sqrt(x: real): real;

The square root of x.

Adds F.class to the JAR, or Real.class with -m2.

See also Sqr

Tan

function Tan(x: real): real;

The tangent of an angle in radians.

Adds F.class to the JAR, or Real.class with -m2.

ToDegrees

function ToDegrees(x: real): real;

Converts an angle from radians to degrees.

Adds F.class to the JAR, or Real.class with -m2.

See also ToRadians

ToRadians

function ToRadians(x: real): real;

Converts an angle from degrees to radians.

Adds F.class to the JAR, or Real.class with -m2.

See also ToDegrees

Trunc

function Trunc(x: real): integer;

The integer part of x, with the fraction dropped. There is no Round; Trunc(x + 0.5) rounds a positive number.

Adds F.class to the JAR, or Real.class with -m2.

See also Frac

Strings

Strings are indexed from 0.

Copy

function Copy(s: string; first, last: integer): string;

The part of s from index first up to, but not including, last. Indexes start at 0, so Copy('MIDletPascal', 2, 5) is 'Dle'. This is not the Copy(s, index, count) of other Pascals.

See also Pos, Length

GetChar

function GetChar(s: string; index: integer): char;

The character at index, counting from 0. Past the end of the string it returns #0.

Adds S.class to the JAR.

See also SetChar

IntegerToString

function IntegerToString(n: integer): string;

The decimal text of n. Adding an integer to a string does the same.

Example
var s: string;
begin
  s := IntegerToString(15);
  s := '' + 15;      { the same }
end.

See also StringToInteger

Length

function Length(s: string): integer;

The number of characters in s. The last one is at index Length(s) - 1.

Locase

function Locase(s: string): string;

s with every letter in lowercase.

See also Upcase

Pos

function Pos(s, part: string): integer;

The index of the first part inside s, or −1 if it is not there. Case matters.

See also Copy

SetChar

function SetChar(s: string; c: char; index: integer): string;

A copy of s with the character at index replaced by c. Past the end of the string it returns s unchanged. Strings cannot be changed in place, so assign the result: s := SetChar(s, 'x', 0).

Adds S.class to the JAR.

See also GetChar

StringToInteger

function StringToInteger(s: string): integer;

Reads a decimal integer: digits, with an optional + or - in front. Anything else gives 0.

Adds S.class to the JAR.

See also IntegerToString

StringToReal

function StringToReal(s: string; base: integer): real;

Reads a real number written in the given base, usually 10.

Adds F.class to the JAR, or Real.class with -m2.

Upcase

function Upcase(s: string): string;

s with every letter in uppercase.

See also Locase

Forms and commands

The screen shows one thing at a time: the canvas, the form, a menu, a text box or an alert. A MIDlet starts on the canvas. The form is a list of items, such as text, fields, gauges and choices, that the FormAdd functions fill and that are referred to by the id they return. Commands sit on the soft keys of any of these screens.

ChoiceAppendString

function ChoiceAppendString(choice: integer; text: string): integer;

Adds an item to a choice group and returns the item's index within the group.

Example
var city, newYork, losAngeles: integer;
begin
  ShowForm;
  city := FormAddChoice('Where do you live?', CH_EXCLUSIVE);
  newYork := ChoiceAppendString(city, 'New York');
  losAngeles := ChoiceAppendString(city, 'Los Angeles');
  Delay(5000);
end.

See also FormAddChoice, ChoiceIsSelected

ChoiceAppendStringImage

function ChoiceAppendStringImage(choice: integer; text: string; img: image): integer;

Adds an item with an image next to its text to a choice group and returns its index.

See also ChoiceAppendString

ChoiceGetSelectedIndex

function ChoiceGetSelectedIndex(choice: integer): integer;

The index of the selected item, or −1 if none is. A CH_MULTIPLE group always answers −1; ask it item by item with ChoiceIsSelected.

See also ChoiceIsSelected

ChoiceIsSelected

function ChoiceIsSelected(choice, item: integer): boolean;

true if item item of the group is selected.

Example
var city, newYork, losAngeles, shown: integer;
begin
  ShowForm;
  city := FormAddChoice('Where do you live?', CH_EXCLUSIVE);
  newYork := ChoiceAppendString(city, 'New York');
  losAngeles := ChoiceAppendString(city, 'Los Angeles');
  Delay(5000);
  if ChoiceIsSelected(city, newYork) then
    shown := FormAddString('New York')
  else
    shown := FormAddString('Los Angeles');
  Delay(2000);
end.

See also ChoiceGetSelectedIndex

ClearForm

procedure ClearForm;

Removes every item and every command from the form.

Adds FS.class to the JAR.

Example
var greeting, name: integer;
begin
  greeting := FormAddString('Hello world');
  name := FormAddTextField('Enter your name', 'Mr. Smith', 20, TF_ANY);
  ShowForm;
  Delay(2000);
  ClearForm;
  Delay(2000);
end.

See also FormRemove

CreateCommand

function CreateCommand(label: string; commandType, priority: integer): command;

Creates a command to put on the screen with AddCommand. Keep the label short. commandType tells the phone what the command means, so that it can put, say, a CM_BACK on the key where the phone keeps “back”: CM_SCREEN, CM_BACK, CM_CANCEL, CM_OK, CM_HELP, CM_STOP, CM_EXIT or CM_ITEM. A lower priority is more important.

Example
var exitCmd, pauseCmd: command;
begin
  exitCmd := CreateCommand('Exit', CM_EXIT, 1);
  pauseCmd := CreateCommand('Pause', CM_SCREEN, 1);
  AddCommand(exitCmd);
  AddCommand(pauseCmd);
  repeat
    Delay(100);
  until GetClickedCommand = exitCmd;
end.

See also AddCommand, GetClickedCommand

EmptyCommand

function EmptyCommand: command;

The value GetClickedCommand returns when nothing was chosen. It is only for comparing: a MIDlet that adds it to the screen crashes.

Example
var ok, clicked: command;
begin
  ok := CreateCommand('OK', CM_OK, 1);
  AddCommand(ok);
  repeat
    clicked := GetClickedCommand;
    Delay(100);
  until clicked <> EmptyCommand;
end.

See also GetClickedCommand

FormAddChoice

function FormAddChoice(label: string; choiceType: integer): integer;

Adds an empty choice group to the form and returns its id; fill it with ChoiceAppendString. With CH_EXCLUSIVE exactly one item is selected, with CH_MULTIPLE any number.

Adds FS.class to the JAR.

See also ChoiceAppendString, ChoiceIsSelected

FormAddDateField

function FormAddDateField(label: string; fieldType: integer): integer;

Adds a date field to the form and returns its id. fieldType is DF_DATE, DF_TIME or DF_DATE_TIME.

Adds FS.class to the JAR.

See also FormGetDate, FormSetDate

FormAddGauge

function FormAddGauge(label: string; interactive: boolean; maxValue, value: integer): integer;

Adds a gauge, a bar from 0 to maxValue, and returns its id. If interactive is false it only shows progress and the user cannot move it.

Adds FS.class to the JAR.

Example
var age: integer;
begin
  age := FormAddGauge('Choose your age', true, 100, 18);
  ShowForm;
  Delay(2000);
end.

See also FormGetValue, FormSetValue

FormAddImage

function FormAddImage(img: image): integer;

Adds an image to the form and returns its id.

Example
var logo: integer;
begin
  logo := FormAddImage(LoadImage('/logo.png'));
  ShowForm;
  Delay(2000);
end.

FormAddSpace

function FormAddSpace: integer;

Adds an empty gap that separates groups of items, and returns its id.

FormAddString

function FormAddString(text: string): integer;

Adds a line of text the user cannot edit, and returns its id.

Example
var greeting: integer;
begin
  greeting := FormAddString('Hello world');
  ShowForm;
  Delay(2000);
end.

See also FormRemove

FormAddTextField

function FormAddTextField(prompt, text: string; maxSize, constraints: integer): integer;

Adds a text field with text already in it and returns its id. maxSize is the most characters it takes. constraints limits what can be typed: TF_ANY, TF_EMAIL, TF_NUMERIC, TF_PHONENUMBER or TF_URL. Adding TF_PASSWORD to any of them hides the text as it is typed.

Adds FS.class to the JAR.

Example
var name: integer;
begin
  name := FormAddTextField('Enter your name', 'Mr. Smith', 20, TF_ANY);
  ShowForm;
  Delay(5000);
  ShowAlert('Hello', FormGetText(name), LoadImage('/icon.png'), ALERT_INFO);
  Delay(2000);
end.

See also FormGetText, FormSetText

FormGetDate

function FormGetDate(field: integer): integer;

The date and time in a date field, as seconds since 1 January 1970, the same number the date functions take.

Adds FS.class to the JAR.

See also FormAddDateField, GetCurrentTime

FormGetText

function FormGetText(field: integer): string;

The text in a text field, or an empty string if field is not a text field.

Adds FS.class to the JAR.

See also FormAddTextField

FormGetValue

function FormGetValue(gauge: integer): integer;

The value of a gauge, or −1 if gauge is not a gauge.

Adds FS.class to the JAR.

See also FormAddGauge

FormRemove

procedure FormRemove(item: integer);

Removes one item from the form.

Example
var name: integer;
begin
  ShowForm;
  name := FormAddTextField('Name', '', 20, TF_ANY);
  Delay(1000);
  FormRemove(name);
  Delay(1000);
end.

See also ClearForm

FormSetDate

procedure FormSetDate(field, time: integer);

Puts a date and time into a date field. For a DF_TIME field, give a time on 1 January 1970, that is, seconds since midnight.

Adds FS.class to the JAR.

See also FormGetDate

FormSetText

procedure FormSetText(field: integer; text: string);

Replaces the text in a text field.

Adds FS.class to the JAR.

See also FormGetText

FormSetValue

procedure FormSetValue(gauge, value: integer);

Sets the value of a gauge.

Adds FS.class to the JAR.

See also FormGetValue

GetClickedCommand

function GetClickedCommand: command;

The command chosen since the previous call, or EmptyCommand if there was none. Reading it clears it.

Example
var exitCmd: command;
begin
  exitCmd := CreateCommand('Exit', CM_EXIT, 1);
  AddCommand(exitCmd);
  repeat
    Delay(100);
  until GetClickedCommand = exitCmd;
end.

See also CreateCommand, EmptyCommand

GetFormTitle

function GetFormTitle: string;

The title of the form, or an empty string if it has none.

Adds FS.class to the JAR.

See also SetFormTitle

GetTextBoxString

function GetTextBoxString: string;

The text in the text box opened by ShowTextBox.

Example
var done: command;
    quote: string;
begin
  ShowTextBox('Your favorite quote', 'To be or not to be', 200, TF_ANY);
  done := CreateCommand('Done', CM_OK, 1);
  AddCommand(done);
  repeat
    Delay(100);
  until GetClickedCommand = done;
  quote := GetTextBoxString;
  ShowCanvas;
  DrawText(quote, 0, 0);
  Repaint;
  Delay(2000);
end.

See also ShowTextBox

MenuAppendString

function MenuAppendString(text: string): integer;

Adds an entry to the menu opened by ShowMenu and returns its index.

Example
var tetris, snake: integer;
    play: command;
begin
  ShowMenu('Select a game', CH_IMPLICIT);
  tetris := MenuAppendString('Tetris');
  snake := MenuAppendString('Snake');
  play := CreateCommand('Play', CM_SCREEN, 1);
  AddCommand(play);
  repeat
    Delay(100);
  until GetClickedCommand = play;
  ShowCanvas;
  if MenuGetSelectedIndex = tetris then DrawText('Tetris', 0, 0)
  else DrawText('Snake', 0, 0);
  Repaint;
  Delay(2000);
end.

See also ShowMenu, MenuGetSelectedIndex

MenuAppendStringImage

function MenuAppendStringImage(text: string; img: image): integer;

Adds an entry with an image next to its text to the menu and returns its index.

See also MenuAppendString

MenuIsSelected

function MenuIsSelected(index: integer): boolean;

true if the menu entry at index is selected. For a CH_MULTIPLE menu this is the only way to ask.

See also MenuGetSelectedIndex

PlayAlertSound

procedure PlayAlertSound;

Plays the sound the phone has for the type of the alert on screen.

See also ShowAlert

SetTicker

procedure SetTicker(text: string);

Scrolls text along the top of the form, like a news ticker.

Example
begin
  ShowForm;
  SetTicker('Made with MIDletPascal');
  Delay(5000);
end.

ShowAlert

procedure ShowAlert(title, message: string; img: image; alertType: alert);

Fills the screen with a message. Only commands can share the screen with an alert; ShowForm or ShowCanvas takes it away. alertType is ALERT_INFO, ALERT_WARNING, ALERT_ERROR, ALERT_ALARM or ALERT_CONFIRMATION.

Example
var read: command;
begin
  ShowAlert('New message', 'Mr. Smith has written to you', LoadImage('/icon.png'), ALERT_INFO);
  PlayAlertSound;
  read := CreateCommand('Read', CM_OK, 1);
  AddCommand(read);
  repeat
    Delay(100);
  until GetClickedCommand = read;
  ShowForm;
end.

See also PlayAlertSound

ShowCanvas

procedure ShowCanvas;

Brings back the canvas, the screen the program draws on. A MIDlet starts on the canvas; ShowForm, ShowMenu, ShowTextBox and ShowAlert replace it until this is called.

Example
var greeting: integer;
begin
  greeting := FormAddString('Hello from the form');
  ShowForm;
  Delay(2000);
  ShowCanvas;
  DrawText('Hello from the canvas', 0, 0);
  Repaint;
  Delay(2000);
end.

See also ShowForm

ShowForm

procedure ShowForm;

Shows the form: the screen of text, fields, choices and images that the FormAdd functions fill. There is one form; it keeps its items while the canvas is shown.

Example
var greeting, name: integer;
begin
  greeting := FormAddString('Hello world');
  name := FormAddTextField('Enter your name', 'Mr. Smith', 20, TF_ANY);
  ShowForm;
  Delay(2000);
end.

See also ShowCanvas, ClearForm

ShowMenu

procedure ShowMenu(title: string; menuType: integer);

Fills the screen with an empty menu, to be filled with MenuAppendString. Only commands can share the screen with it. CH_IMPLICIT is an ordinary list to pick from; CH_EXCLUSIVE shows a radio button next to each entry and CH_MULTIPLE a check box.

See also MenuAppendString, MenuGetSelectedIndex

ShowTextBox

procedure ShowTextBox(title, text: string; maxSize, constraints: integer);

Fills the screen with a text editor holding text. Only commands can share the screen with it. constraints takes the same TF_ constants as FormAddTextField.

See also GetTextBoxString

Record stores

A record store is a named list of strings that the phone keeps after the MIDlet exits: saved games, settings, high scores. Each record has an index starting at 1.

AddRecordStoreEntry

function AddRecordStoreEntry(rs: recordStore; data: string): integer;

Adds a record and returns its index, or −1 if it could not be stored. The first record of a store is 1.

Adds RS.class to the JAR.

Example
var rs: recordStore;
    index: integer;
begin
  rs := OpenRecordStore('scores');
  index := AddRecordStoreEntry(rs, 'Alice 1200');
  CloseRecordStore(rs);
end.

See also ReadRecordStoreEntry, ModifyRecordStoreEntry

CloseRSEnumeration not in mp3cc

procedure CloseRSEnumeration(enum: integer);

mp3cc does not accept it. The original manual lists the enumeration routines, but MIDletPascal 3.5, and so mp3cc, does not have them. Go through the records by index from 1 to GetRecordStoreNextId − 1 and skip the empty ones.

DeleteRecordStore

procedure DeleteRecordStore(name: string);

Deletes a whole record store with everything in it. Nothing happens if there is no store of that name.

Adds RS.class to the JAR.

DeleteRecordStoreEntry

procedure DeleteRecordStoreEntry(rs: recordStore; index: integer);

Deletes one record. Its index is not reused, so the indexes of the other records do not change.

Adds RS.class to the JAR.

See also AddRecordStoreEntry

EnumerateRecords not in mp3cc

function EnumerateRecords(rs: recordStore): integer;

mp3cc does not accept it. The original manual lists the enumeration routines, but MIDletPascal 3.5, and so mp3cc, does not have them. Go through the records by index from 1 to GetRecordStoreNextId − 1 and skip the empty ones.

GetRecordStoreNextId

function GetRecordStoreNextId(rs: recordStore): integer;

The index the next AddRecordStoreEntry will give. Every index below it has been used, though some may have been deleted since.

Adds RS.class to the JAR.

Example
var rs: recordStore;
    i: integer;
    data: string;
begin
  rs := OpenRecordStore('scores');
  for i := 1 to GetRecordStoreNextId(rs) - 1 do
  begin
    data := ReadRecordStoreEntry(rs, i);
    if data <> '' then Debug(data);
  end;
  CloseRecordStore(rs);
end.

See also GetRecordStoreSize

GetRecordStoreSize

function GetRecordStoreSize(rs: recordStore): integer;

The number of records in the store. After a delete this is less than the highest index, so loop up to GetRecordStoreNextId instead.

Adds RS.class to the JAR.

See also GetRecordStoreNextId

NextRecord not in mp3cc

function NextRecord(enum: integer): string;

mp3cc does not accept it. The original manual lists the enumeration routines, but MIDletPascal 3.5, and so mp3cc, does not have them. Go through the records by index from 1 to GetRecordStoreNextId − 1 and skip the empty ones.

OpenRecordStore

function OpenRecordStore(name: string): recordStore;

Opens the record store called name, creating an empty one the first time. A record store is the phone's storage for a MIDlet: it keeps its records after the MIDlet exits, until it is deleted with DeleteRecordStore or the MIDlet is uninstalled.

Adds RS.class to the JAR.

See also CloseRecordStore, AddRecordStoreEntry

ReadRecordStoreEntry

function ReadRecordStoreEntry(rs: recordStore; index: integer): string;

The record at index, or an empty string if there is none.

Adds RS.class to the JAR.

See also GetRecordStoreNextId

UpdateRSEnumeration not in mp3cc

procedure UpdateRSEnumeration(enum: integer);

mp3cc does not accept it. The original manual lists the enumeration routines, but MIDletPascal 3.5, and so mp3cc, does not have them. Go through the records by index from 1 to GetRecordStoreNextId − 1 and skip the empty ones.

HTTP

A request is built up on an http variable: open it, set the method and the headers, send it, read the answer, close it.

AddHttpBody

procedure AddHttpBody(conn: http; data: string);

Adds data to the body of the request. Only a POST carries a body.

Adds H.class to the JAR.

See also SetHttpMethod

AddHttpHeader

procedure AddHttpHeader(conn: http; name, value: string);

Adds a header to the request, for example AddHttpHeader(conn, 'Accept', 'text/plain').

Adds H.class to the JAR.

CloseHttp

procedure CloseHttp(conn: http);

Closes the connection.

Adds H.class to the JAR.

See also OpenHttp

GetHttpHeader

function GetHttpHeader(conn: http; name: string): string;

The value of a header of the response: GetHttpHeader(conn, 'Content-Type') might return 'text/plain'.

Adds H.class to the JAR.

IsHttpOpen

function IsHttpOpen(conn: http): boolean;

true if the connection is open.

OpenHttp

function OpenHttp(conn: http; url: string): boolean;

Opens a connection to url, written as http://host[:port][/path]. Returns false if it fails. A phone usually asks the user before a MIDlet goes online.

Adds H.class to the JAR.

Example
var conn: http;
    page: string;
begin
  if OpenHttp(conn, 'http://example.com/') then
  begin
    SetHttpMethod(conn, GET);
    if SendHttpMessage(conn) = 200 then
      page := GetHttpResponse(conn);
    CloseHttp(conn);
  end;
end.

See also SendHttpMessage, CloseHttp

SendHttpMessage

function SendHttpMessage(conn: http): integer;

Sends the request, waits for the answer and returns the HTTP status code, such as 200 for success or 404 for a missing page, or −1 if the request could not be made.

Adds H.class to the JAR.

See also GetHttpResponse

SetHttpMethod

procedure SetHttpMethod(conn: http; method: string);

Sets the request method: GET, POST or HEAD, which are predefined string constants.

Adds H.class to the JAR.

SMS

SmsIsSending

function SmsIsSending: boolean;

true while a message started with SmsStartSend is still being sent.

Adds SM.class to the JAR.

See also SmsStartSend

SmsStartSend

function SmsStartSend(destination, message: string): boolean;

Starts sending a text message and returns at once. destination is written sms://+number. Returns false if the message could not be handed over, for example because another one is still on its way. MIDletPascal sends through the Wireless Messaging API or the Siemens API; a phone with neither cannot send at all.

Adds SM.class to the JAR.

Example
begin
  if not SmsStartSend('sms://+5550000', 'Hello!') then Halt;
  while SmsIsSending do
    Delay(100);
  if not SmsWasSuccessfull then Halt;
end.

See also SmsIsSending, SmsWasSuccessfull

SmsWasSuccessfull

function SmsWasSuccessfull: boolean;

true if the last message was sent. false means the phone cannot send messages from a MIDlet, the number is wrong, or the network refused it. The name is spelled with two l's.

Adds SM.class to the JAR.

See also SmsStartSend

Sound

These need a MIDP 2.0 phone, or one with MMAPI. On an older phone a MIDlet that uses them crashes.

GetPlayerDuration

function GetPlayerDuration: integer;

The length of the loaded sound in milliseconds.

Adds P.class to the JAR.

See also OpenPlayer

OpenPlayer

function OpenPlayer(name, mimeType: string): boolean;

Loads a sound from the JAR; StartPlayer plays it. Returns false if it fails. There is a single player, and opening a sound closes the one before it, so music stops for every effect. For several sounds at once, use the Sound library.

  • MIDI: audio/midi
  • WAV: audio/x-wav
  • MP3: audio/mpeg
  • AU: audio/basic

Phones rarely play all of them.

Adds P.class to the JAR.

Example
begin
  if not OpenPlayer('/explosion.mid', 'audio/midi') then Halt;
  if not SetPlayerCount(-1) then Halt;
  if not StartPlayer then Halt;
  Delay(5000);
end.

See also StartPlayer, StopPlayer

PlayTone

procedure PlayTone(note, duration, volume: integer);

Plays one tone. note is a MIDI note number from 0 to 127, where 69 is the A at 440 Hz; duration is in milliseconds and volume 0 to 100. The original manual does not mention it.

SetPlayerCount

function SetPlayerCount(count: integer): boolean;

How many times the loaded sound plays, −1 for endlessly. Call it between OpenPlayer and StartPlayer.

Adds P.class to the JAR.

See also OpenPlayer

StartPlayer

function StartPlayer: boolean;

Plays the sound loaded with OpenPlayer. Returns false if it cannot.

Adds P.class to the JAR.

See also OpenPlayer, StopPlayer

StopPlayer

procedure StopPlayer;

Stops the sound that is playing.

Adds P.class to the JAR.

See also StartPlayer

Resource files

Resources are files packed into the JAR, read one byte or one line at a time.

OpenResource

function OpenResource(name: string): resource;

Opens a file from the JAR for reading. As with LoadImage, the name starts with /; in ANPASIDE the files of a project's res/ folder go into the JAR. Check ResourceAvailable before reading.

Adds S.class to the JAR.

Example
var res: resource;
    line: string;
    shown: integer;
begin
  res := OpenResource('/data.txt');
  if ResourceAvailable(res) then
  begin
    line := ReadLine(res);
    CloseResource(res);
  end;
  ShowForm;
  shown := FormAddString('First line: ' + line);
  Delay(2000);
end.

See also ReadLine, ReadByte

ReadByte

function ReadByte(res: resource): integer;

The next byte, 0 to 255, or EOF at the end of the file or on an error.

See also ReadLine

ReadLine

function ReadLine(res: resource): string;

The next line of text. At the end of the file, or on an error, it returns an empty string. Empty lines are skipped, so an empty result always means the end.

See also ReadByte

Other

Assert

procedure Assert(condition: boolean);

If condition is false, writes a line such as Assertion failed at: game.pas:162 to the debug output.

See also Debug

Chr

function Chr(code: integer): char;

The character with the given ASCII code, 0 to 127.

See also Ord

Debug

procedure Debug(text: string);

Writes text to the emulator's standard output. A phone ignores it.

GetProperty

function GetProperty(name: string): string;

A Java system property of the phone, for example microedition.locale or microedition.platform; an empty string if the phone does not have it.

Example
begin
  Debug(GetProperty('microedition.locale'));
end.

Halt

procedure Halt;

Ends the MIDlet.

IsMidletPaused

function IsMidletPaused: boolean;

true while the phone has paused the MIDlet, for example during a call. A game checks it to stop its clock until the MIDlet comes back.

Example
  repeat
    { ... keys, timers, drawing ... }
    while IsMidletPaused do
      Delay(100);
  until gameOver;

Odd

function Odd(n: integer): boolean;

true if n is odd.

Ord

function Ord(c: char): integer;

The ASCII code of a character.

See also Chr

Random

function Random(n: integer): integer;

A random integer from 0 to n − 1.

Example
{ true three times out of four }
function likely: boolean;
begin
  likely := Random(4) <> 3;
end;

See also Randomize

Randomize

procedure Randomize;

Seeds the random number generator again. A MIDlet already does it once at start.

See also Random

Libraries

The routines of the libraries ANPASIDE ships. Each one is reached with uses, as described in Libraries in ANPASIDE.

Touch
Init touch_count touch_down touch_x touch_y touch_pressed touch_released touch_area pointer_*
Sound
sound_open sound_play sound_pause sound_resume sound_stop sound_loop sound_volume sound_playing sound_duration sound_close
Screen
screen_inset_*

Touch

Reached with uses Touch;. See Touch for what the library needs from the runtime.

Init

procedure Init;

Makes the library's canvas the current screen, as Sensor.Init does, and forgets every finger. Call it once, as Touch.Init, before drawing anything.

touch_count

function touch_count: integer;

The number of fingers on the screen right now.

See also touch_down

touch_down

function touch_down(n: integer): integer;

1 while finger n is on the screen, otherwise 0. Fingers are numbered 0 to 9; any other n gives 0.

Example
for i := 0 to 9 do
  if touch_down(i) = 1 then
    FillRect(touch_x(i) - 10, touch_y(i) - 10, 20, 20);

See also touch_x

touch_x

function touch_x(n: integer): integer;

The last x of finger n. It stays where the finger was lifted, so check touch_down first.

See also touch_y

touch_y

function touch_y(n: integer): integer;

The last y of finger n. It stays where the finger was lifted, so check touch_down first.

See also touch_x

touch_pressed

function touch_pressed(n: integer): integer;

1 if finger n has touched the screen since the previous call for that finger, otherwise 0. Unlike touch_down, it does not miss a tap shorter than a frame. Reading it clears it, so read each finger once per frame and keep the result.

Example
uses Touch;
var i, taps: integer;
begin
  Touch.Init;
  taps := 0;
  repeat
    for i := 0 to 9 do
      if touch_pressed(i) = 1 then taps := taps + 1;
    { ... draw, Repaint, Delay ... }
  until false;
end.

See also touch_released

touch_released

function touch_released(n: integer): integer;

1 if finger n has been lifted since the previous call for that finger, otherwise 0. Reading it clears it, as with touch_pressed.

See also touch_pressed

touch_area

function touch_area(x, y, w, h: integer): integer;

The number of fingers inside the rectangle at x, y of size w × h. An on-screen button is held while this is above 0, whichever finger holds it, so several buttons can be held at once.

Example
{ a jump button in the lower right corner }
if touch_area(GetWidth - 80, GetHeight - 80, 80, 80) > 0 then
  Jump;

pointer_*

function has_pointer_events: integer;
function has_pointer_motion_events: integer;
function pointer_state: integer;
function pointer_pressed_x: integer;
function pointer_pressed_y: integer;
function pointer_dragged_x: integer;
function pointer_dragged_y: integer;
function pointer_released_x: integer;
function pointer_released_y: integer;

The functions of Lib_sensor, under the same names and with the same meaning, for finger 0 only. pointer_state is 1 while finger 0 is down, and a second finger does not change any of them, so do not mix them with touch_area, which counts every finger.

Sound

Reached with uses Sound;. Channels are numbered 0 to 7. A call with any other number does nothing and reports failure: 0, or −1 from sound_duration.

sound_open

function sound_open(ch: integer; name, mimeType: string): integer;

Loads the sound name from the JAR into channel ch, 0 to 7, and closes what the channel held before. Returns 1 on success, 0 if the channel, the file or the type is wrong. The types are audio/midi, audio/x-wav, audio/mpeg, audio/aac, audio/mp4 and audio/amr.

Example
ok := sound_open(0, '/music.mid', 'audio/midi');
ok := sound_open(1, '/coin.wav', 'audio/x-wav');

See also sound_play

sound_play

function sound_play(ch: integer): integer;

Plays channel ch from the start. If it is already playing it starts over, so an effect fired twice cuts its first run short. Returns 1 on success, otherwise 0.

See also sound_stop

sound_pause

procedure sound_pause(ch: integer);

Pauses channel ch; sound_resume continues from the same place. The other channels keep playing.

See also sound_resume

sound_resume

function sound_resume(ch: integer): integer;

Continues channel ch where sound_pause stopped it. Returns 1 on success, otherwise 0.

See also sound_pause

sound_stop

procedure sound_stop(ch: integer);

Stops channel ch and rewinds it.

See also sound_play

sound_loop

procedure sound_loop(ch, count: integer);

How many times channel ch plays in a row, −1 for endlessly; 1 at first. It takes effect at the next sound_play and stays with the channel through sound_open.

sound_volume

procedure sound_volume(ch, level: integer);

The volume of channel ch, 0 to 100; 100 at first. It takes effect at once and stays with the channel through sound_open.

Example
sound_volume(0, 40);  { the music quieter than the effects }

sound_playing

function sound_playing(ch: integer): integer;

1 while channel ch is playing, otherwise 0.

sound_duration

function sound_duration(ch: integer): integer;

The length of the sound on channel ch in milliseconds, or −1 if it is not known. ANPASIDE's emulator only knows it while the sound plays, and answers 0 before that.

sound_close

procedure sound_close(ch: integer);

Stops channel ch and frees its sound. The channel can be opened again.

See also sound_open

Screen

Reached with uses Screen;.

screen_inset_*

function screen_inset_left: integer;
function screen_inset_top: integer;
function screen_inset_right: integer;
function screen_inset_bottom: integer;

How far the camera cutout or a rounded corner reaches into that edge of the canvas, in canvas pixels, or 0. A control kept at least that far from every edge is seen whole. The values follow the screen when it turns. Outside ANPASIDE's emulator and the APKs it exports they are always 0.

Example
{ a menu button the top right corner does not cut off }
DrawImage(menu, GetWidth - screen_inset_right - GetImageWidth(menu), screen_inset_top);

APredefined constants

Every program has these without declaring them.

Game actions, from KeyToAction
GA_NONE0
GA_UP1
GA_LEFT2
GA_RIGHT5
GA_DOWN6
GA_FIRE8
GA_GAMEA9
GA_GAMEB10
GA_GAMEC11
GA_GAMED12
Keys, from GetKeyClicked
KE_NONE0
KE_KEY0 … KE_KEY948 … 57
KE_STAR42
KE_POUND35
Font faces, for SetFont
FONT_FACE_SYSTEM0
FONT_FACE_MONOSPACE32
FONT_FACE_PROPORTIONAL64
Font styles, joined with or
FONT_STYLE_PLAIN0
FONT_STYLE_BOLD1
FONT_STYLE_ITALIC2
FONT_STYLE_UNDERLINED4
Font sizes
FONT_SIZE_MEDIUM0
FONT_SIZE_SMALL8
FONT_SIZE_LARGE16
Command types, for CreateCommand
CM_SCREEN1
CM_BACK2
CM_CANCEL3
CM_OK4
CM_HELP5
CM_STOP6
CM_EXIT7
CM_ITEM8
Text constraints, for FormAddTextField
TF_ANY0
TF_EMAIL1
TF_NUMERIC2
TF_PHONENUMBER3
TF_URL4
TF_PASSWORD$10000
Choice types, for FormAddChoice and ShowMenu
CH_EXCLUSIVE1
CH_MULTIPLE2
CH_IMPLICIT3
Date fields, for FormAddDateField
DF_DATE1
DF_TIME2
DF_DATE_TIME3
Alert types, for ShowAlert
ALERT_INFO
ALERT_WARNING
ALERT_ERROR
ALERT_ALARM
ALERT_CONFIRMATION
Other
pi3.14159…
EOF1000
GET'GET'
POST'POST'
HEAD'HEAD'

BKey scan codes

The codes GetKeyPressed and GetKeyClicked return. The number keys, * and # are the same everywhere; the others depend on the maker, which is why there is KeyToAction.

KeySiemensSony EricssonNokiaMotorola
0 to 948–5748–5748–5748–57
* and #42, 3542, 3542, 3542, 35
Up−59−1−11 (−1)
Down−60−2−26 (−2)
Left−61−3−32 (−3)
Right−62−4−45 (−4)
Fire−26−5−520 (−5)
Left soft key−1−621
Right soft key−4−722
Clear−8−80