API.md 8.1 KB

tvision-m2 - API reference

All names are in module tv. Import it qualified (IMPORT tv;) or with FROM tv IMPORT .... Every drawing call draws into an off-screen cell buffer; nothing reaches the terminal until Present (or Finish).

Lifecycle

procedure description
Init() : BOOLEAN enter raw mode + alternate screen, install SIGWINCH handler, create the desktop. FALSE if stdin is not a tty.
Done leave the alternate screen and restore the terminal.
Cols() / Rows() : INTEGER current screen size.
Resized() : BOOLEAN TRUE if the terminal size changed or SIGWINCH fired since the last call (also re-clears the screen). Call it in your loop.
Finish DrawTree + Present (redraw everything and flush).
DrawTree draw the desktop, all views and the menu bar into the cell buffer.
Present flush the diff to the terminal.

Colours and attributes

16 colours: Black Blue Green Cyan Red Magenta Brown LightGray DarkGray LightBlue LightGreen LightCyan LightRed LightMagenta Yellow White. A(fg, bg : INTEGER; blink : BOOLEAN) : Attr builds an attribute. Frame styles: SingleFrame, DoubleFrame.

Low-level screen

Clear(attr), Fill(x,y,w,h, cp, attr), DrawCh(x,y,cp,attr), DrawText(x,y, s, attr), DrawBox(r, style, attr), DrawShadow(r, attr), SetCursor(x,y), HideCursor. cp is a Unicode code point (CARDINAL); ASCII text can use VAL(CARDINAL, ORD(ch)).

Text helpers

TextLen(s) : INTEGER, CopyText(dest, s), AppendText(dest, s), PadText(dest, s, width), IntToText(dest, n, width).

Events

TYPE Event = RECORD
       kind : EventKind;        (* evNone evKey evMouse *)
       key  : INTEGER;          (* kChar kUp kDown kLeft kRight kHome kEnd
                                   kPgUp kPgDn kIns kDel kEnter kEsc kTab
                                   kBack kSpace kF1..kF12 kCtrlC kNone *)
       ch   : CARDINAL;         (* code point for kChar *)
       ctrl : BOOLEAN;          (* e.g. Shift-Tab gives kTab with ctrl=TRUE *)
       mx, my : INTEGER;        (* mouse position, 0-based *)
       mbtn : INTEGER;          (* 1 left, 2 middle, 3 right; held button during motion *)
       mpressed, mreleased : BOOLEAN;
       mwheel : INTEGER;        (* -1 up, +1 down *)
     END;

ReadEvent(e) : BOOLEAN waits up to ~0.1 s and returns FALSE on timeout.

HandleEvent(e) : INTEGER dispatches one event to the menu bar, the modal dialog (if any) or the desktop, and returns a command: cmNone, cmClose, or the tag of the activated control/menu item. Sender() : ViewPtr returns the view that produced it (NIL for menus).

Built-in commands: cmNone cmClose cmOK cmCancel cmYes cmNo.

View tree

TYPE VKind = (VGroup, VWindow, VText, VFrame, VInput, VButton,
              VCheck, VRadio, VList, VScroll);
     View = RECORD ... END;  ViewPtr = POINTER TO View;
procedure description
NewView(kind, x,y,w,h) : ViewPtr allocate a view (absolute screen coordinates).
AddView(parent, child) append a child to a group/window.
DelView(v) remove a view and its children.
SetText(v, s) / SetTag(v, n) set text / command tag.
Desk() : ViewPtr the desktop group; add top-level windows here.
BringToFront(v) raise within its parent (z-order).
FocusView(v) / FocusNext(backwards) set/advance keyboard focus.
MoveViewBy(v, dx, dy) move a view and its descendants.

Fields are public: v^.rect, v^.text, v^.flags, v^.value, v^.minv, v^.maxv, v^.tag, v^.list, v^.focus. Flags: vfDisabled, vfSelected, vfFramed.

Widget kinds: VText (label), VFrame (box), VInput, VButton, VCheck, VRadio, VList (needs v^.list : ListDataPtr), VScroll (v^.value/minv/maxv), VWindow, VGroup.

TYPE ListData = RECORD
         items : ARRAY [0..255] OF ARRAY [0..63] OF CHAR;
         count : INTEGER;
     END;  ListDataPtr = POINTER TO ListData;

Editor

TYPE EditorData = RECORD ... END; EditorDataPtr = POINTER TO EditorData;

Declare one EditorData (a few tens of KB) per editor, attach it to a VEditor view, and it becomes a full multi-line editor with its own frame and a Ln/Col/Insert/Modified status row.

VAR ed : tv.EditorData; edp : tv.EditorDataPtr;
...
edp := CAST(tv.EditorDataPtr, ADR(ed));
tv.EditorInit(edp);                    (* empty; or EditorLoad below *)
tv.EditorAddLine(edp, "MODULE hello;");  (* build sample text *)
ev := tv.NewView(tv.VEditor, 2, 2, 60, 20);
tv.EditorAttach(ev, edp);
tv.AddView(win, ev);
tv.FocusView(ev);
procedure description
EditorAttach(v, data) tie an editor buffer to a VEditor view
EditorInit(data) clear to a single empty line
EditorAddLine(data, s) append a line (for building text)
EditorGetLine(data, i, VAR s) read a line back
EditorLoad(data, path) : BOOLEAN load a text file into the buffer
EditorSave(data, path) : BOOLEAN save the buffer to a text file
EditorDirty(data) : BOOLEAN TRUE if modified since load/save
EditorSetLanguage(data, lang) enable highlighting for a language

Language constants: langNone, langModula2, langPascal, langOberon. With a language set the editor highlights keywords (white), strings (red), comments (grey; (* ... *) nestable, plus { ... } for Pascal and // for Pascal/Modula-2) and numbers (red). For Modula-2 and Oberon, finishing a word with a delimiter (space, Tab, Enter or punctuation) automatically upper-cases it if it is a keyword (begin -> BEGIN).

Keys: printable text, Enter, Backspace, Delete, arrows, Home/End, PgUp/PgDn, Tab (indent to a 4-column stop), Ins (insert/overwrite). The mouse places the cursor and the wheel scrolls.

Menus

MenuBarInit, MenuAdd(title), MenuItemAdd(text, tag), MenuSep, MenuBar(show : BOOLEAN). The menu bar is drawn on row 0; selecting an item makes HandleEvent return its tag. Mouse: click a title, click an item. Keyboard: F10, arrows, Enter/Space, Esc.

Dialogs

Build a centred modal window, add controls, then run it:

tv.Dialog("Options", 44, 12);
iName := tv.DlgInput("Name:", "Modula-2");   (* -> field index *)
cOn   := tv.DlgCheck("Enabled", TRUE);
rFast := tv.DlgRadio("Fast", TRUE);          (* radios auto-exclusive *)
rSafe := tv.DlgRadio("Safe", FALSE);
tv.DlgButton("OK", tv.cmOK);
tv.DlgButton("Cancel", tv.cmCancel);
cmd := tv.DlgRun;                             (* blocks; returns the tag *)
tv.DlgTextAt(iName, s);                       (* read an input *)
n := tv.DlgValue(cOn);                        (* 1 if selected *)

DlgRun returns the pressed button's tag, cmCancel on Esc, cmClose from the close box.

Message boxes

MessageBox(title, text, kind) : INTEGER where kind is mbOK, mbOKCancel or mbYesNo; returns cmOK, cmCancel, cmYes or cmNo. Message(title, text) is shorthand for MessageBox(..., mbOK).

Graphics backend (tvg)

tvg renders the same view tree into a tigr window instead of a terminal. Terminal programs do not link tigr.

IMPORT tv, tvg;
...
tvg.InitGfx("my app", 90, 30);   (* title, grid cols x rows *)
... build views with tv as usual ...
tvg.Finish;
WHILE ... DO
    IF tvg.ReadEvent(e) THEN cmd := tv.HandleEvent(e); ...; tvg.Finish END;
    IF tvg.Closed() THEN quit := TRUE END
END;
tvg.Done

Use tv.InitVirtual(cols, rows) (not tv.Init) when driving tv from a non-terminal backend; it sets the virtual screen size without touching the tty. tvg maps tigr keys and mouse to the same tv.Event; the cell grid is tv.Cols() x tv.Rows(), each cell CellW() x CellH() pixels. Text is drawn from tvfont (a bundled 8x16 monospaced VGA font, so no system font is required); box-drawing cells are rendered as line segments.

Building against the library

gm2 -fiso -c tvtty.def
gm2 -fiso -I. -c tv.mod
gm2 -fiso -I. tv.o myapp.mod -o myapp

For the graphics backend also build tvg.o (needs the tigr binding):

gm2 -fiso -I. -c tvfont.mod
gm2 -fiso -I. -I../modula2 -c tvg.mod
gm2 -fiso -I. -I../modula2 tv.o tvg.o tvfont.o \
     ../modula2/tigr.o ../modula2/helper.o myapp.mod -o myapp -lGL -lX11