# 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 | | `EditorSetIndent(data, n)` | auto-indent step in spaces (default 2; 0 = off) | 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`). Auto-indentation (when a language is set): Enter copies the current line's leading spaces and adds one indent step after an open keyword (`BEGIN`, `THEN`, `ELSE`, `ELSIF`, `DO`, `LOOP`, `REPEAT`, `RECORD`, `CASE`, `OF`); a line whose first word is a close keyword (`END`, `UNTIL`, `ELSE`, `ELSIF`) is dedented one step. Configure the step with `EditorSetIndent`. 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