|
|
@@ -4,7 +4,7 @@ IMPLEMENTATION MODULE tv;
|
|
|
See tv.def. Pure ISO GNU Modula-2 apart from the libc binding tvtty.def. *)
|
|
|
|
|
|
FROM SYSTEM IMPORT ADDRESS, ADR, ADDADR, CAST, BYTE;
|
|
|
-FROM tvtty IMPORT tcgetattr, tcsetattr, ioctl, read, write;
|
|
|
+FROM tvtty IMPORT tcgetattr, tcsetattr, ioctl, read, write, signal;
|
|
|
|
|
|
CONST
|
|
|
MAXROWS = 120;
|
|
|
@@ -78,6 +78,15 @@ VAR
|
|
|
menuSel : INTEGER;
|
|
|
menuShown : BOOLEAN;
|
|
|
|
|
|
+ winch : BOOLEAN;
|
|
|
+ oldWinch : ADDRESS;
|
|
|
+
|
|
|
+ dlg : ViewPtr;
|
|
|
+ dlgW : INTEGER;
|
|
|
+ dlgWX, dlgWY, dlgX, dlgY, dlgInputX, dlgBtnX, dlgBtnY : INTEGER;
|
|
|
+ dlgItems : ARRAY [0..31] OF ViewPtr;
|
|
|
+ dlgCount : INTEGER;
|
|
|
+
|
|
|
(*========================================================================*)
|
|
|
(* libc struct helpers *)
|
|
|
(*========================================================================*)
|
|
|
@@ -200,6 +209,11 @@ END FlushOut;
|
|
|
(* Terminal setup *)
|
|
|
(*========================================================================*)
|
|
|
|
|
|
+PROCEDURE OnWinch (sig : INTEGER);
|
|
|
+BEGIN
|
|
|
+ winch := TRUE
|
|
|
+END OnWinch;
|
|
|
+
|
|
|
PROCEDURE Init() : BOOLEAN;
|
|
|
VAR lf, iff : CARDINAL; i : INTEGER;
|
|
|
BEGIN
|
|
|
@@ -222,6 +236,9 @@ BEGIN
|
|
|
clipN := 0;
|
|
|
modal := NIL; dragWin := NIL; lastSender := NIL;
|
|
|
menuCount := 0; menuOpen := -1; menuSel := 0; menuShown := FALSE;
|
|
|
+ winch := FALSE;
|
|
|
+ oldWinch := signal(28, ADR(OnWinch));
|
|
|
+ dlg := NIL; dlgCount := 0;
|
|
|
(* reset view pool *)
|
|
|
FOR i := 0 TO MAXVIEWS - 1 DO used[i] := FALSE END;
|
|
|
desk := NIL;
|
|
|
@@ -255,10 +272,12 @@ PROCEDURE Rows() : INTEGER;
|
|
|
BEGIN RETURN rows END Rows;
|
|
|
|
|
|
PROCEDURE Resized() : BOOLEAN;
|
|
|
- VAR r, c : INTEGER;
|
|
|
+ VAR r, c : INTEGER; changed : BOOLEAN;
|
|
|
BEGIN
|
|
|
GetWinSize(r, c);
|
|
|
- IF (r # rows) OR (c # cols) THEN
|
|
|
+ changed := winch OR (r # rows) OR (c # cols);
|
|
|
+ winch := FALSE;
|
|
|
+ IF changed THEN
|
|
|
rows := r; cols := c;
|
|
|
prevValid := FALSE;
|
|
|
Clear(A(LightGray, Blue, FALSE));
|
|
|
@@ -1358,6 +1377,23 @@ BEGIN
|
|
|
END
|
|
|
END EditKey;
|
|
|
|
|
|
+PROCEDURE SelectRadio(v : ViewPtr);
|
|
|
+ VAR c : ViewPtr;
|
|
|
+BEGIN
|
|
|
+ IF (v = NIL) OR (v^.parent = NIL) THEN RETURN END;
|
|
|
+ c := v^.parent^.first;
|
|
|
+ WHILE c # NIL DO
|
|
|
+ IF (c # v) AND (c^.kind = VRadio) AND
|
|
|
+ ((c^.flags DIV vfSelected) MOD 2 = 1) THEN
|
|
|
+ c^.flags := c^.flags - vfSelected
|
|
|
+ END;
|
|
|
+ c := c^.next
|
|
|
+ END;
|
|
|
+ IF (v^.flags DIV vfSelected) MOD 2 = 0 THEN
|
|
|
+ v^.flags := v^.flags + vfSelected
|
|
|
+ END
|
|
|
+END SelectRadio;
|
|
|
+
|
|
|
PROCEDURE WidgetKey(v : ViewPtr; VAR e : Event) : INTEGER;
|
|
|
VAR cmd : INTEGER;
|
|
|
BEGIN
|
|
|
@@ -1375,7 +1411,10 @@ BEGIN
|
|
|
cmd := v^.tag
|
|
|
END
|
|
|
ELSIF v^.kind = VRadio THEN
|
|
|
- IF (e.key = kEnter) OR (e.key = kSpace) THEN cmd := v^.tag END
|
|
|
+ IF (e.key = kEnter) OR (e.key = kSpace) THEN
|
|
|
+ SelectRadio(v);
|
|
|
+ cmd := v^.tag
|
|
|
+ END
|
|
|
ELSIF v^.kind = VList THEN
|
|
|
IF e.key = kUp THEN
|
|
|
IF v^.value > 0 THEN v^.value := v^.value - 1 END;
|
|
|
@@ -1424,7 +1463,10 @@ BEGIN
|
|
|
cmd := v^.tag
|
|
|
END
|
|
|
ELSIF v^.kind = VRadio THEN
|
|
|
- IF e.mreleased THEN cmd := v^.tag END
|
|
|
+ IF e.mreleased THEN
|
|
|
+ SelectRadio(v);
|
|
|
+ cmd := v^.tag
|
|
|
+ END
|
|
|
ELSIF v^.kind = VList THEN
|
|
|
IF e.mwheel # 0 THEN
|
|
|
IF (e.mwheel < 0) AND (v^.pos > 0) THEN v^.pos := v^.pos - 1 END;
|
|
|
@@ -1563,42 +1605,178 @@ BEGIN RETURN lastSender END Sender;
|
|
|
(* Modal message box *)
|
|
|
(*========================================================================*)
|
|
|
|
|
|
-PROCEDURE Message (title : ARRAY OF CHAR; text : ARRAY OF CHAR);
|
|
|
- VAR w, t, b : ViewPtr; e : Event;
|
|
|
- tw, ww, wx, wy : INTEGER; cmd : INTEGER; done : BOOLEAN;
|
|
|
-BEGIN
|
|
|
- tw := TextLen(text);
|
|
|
- ww := tw + 6;
|
|
|
- IF ww < 24 THEN ww := 24 END;
|
|
|
- IF ww > cols - 4 THEN ww := cols - 4 END;
|
|
|
- wx := (cols - ww) DIV 2; wy := (rows - 7) DIV 2;
|
|
|
- w := NewView(VWindow, wx, wy, ww, 7);
|
|
|
- SetText(w, title);
|
|
|
- t := NewView(VText, wx + 2, wy + 2, ww - 4, 1);
|
|
|
- SetText(t, text);
|
|
|
- AddView(w, t);
|
|
|
- b := NewView(VButton, wx + (ww - 8) DIV 2, wy + 4, 8, 1);
|
|
|
- SetText(b, "OK");
|
|
|
- SetTag(b, cmOK);
|
|
|
- AddView(w, b);
|
|
|
- AddView(desk, w);
|
|
|
- BringToFront(w);
|
|
|
- FocusView(b);
|
|
|
- modal := w;
|
|
|
- done := FALSE;
|
|
|
+(*========================================================================*)
|
|
|
+(* Generic dialog builder *)
|
|
|
+(*========================================================================*)
|
|
|
+
|
|
|
+PROCEDURE NewDlgItem (k : VKind; x, y, w, h : INTEGER;
|
|
|
+ text : ARRAY OF CHAR) : ViewPtr;
|
|
|
+ VAR v : ViewPtr;
|
|
|
+BEGIN
|
|
|
+ v := NewView(k, x, y, w, h);
|
|
|
+ SetText(v, text);
|
|
|
+ AddView(dlg, v);
|
|
|
+ IF dlgCount < 32 THEN
|
|
|
+ dlgItems[dlgCount] := v;
|
|
|
+ dlgCount := dlgCount + 1
|
|
|
+ END;
|
|
|
+ RETURN v
|
|
|
+END NewDlgItem;
|
|
|
+
|
|
|
+PROCEDURE Dialog (title : ARRAY OF CHAR; w, h : INTEGER);
|
|
|
+ VAR x, y : INTEGER;
|
|
|
+BEGIN
|
|
|
+ x := (cols - w) DIV 2;
|
|
|
+ y := (rows - h) DIV 2;
|
|
|
+ IF x < 0 THEN x := 0 END;
|
|
|
+ IF y < 0 THEN y := 0 END;
|
|
|
+ dlg := NewView(VWindow, x, y, w, h);
|
|
|
+ SetText(dlg, title);
|
|
|
+ dlgW := w; dlgWX := x; dlgWY := y;
|
|
|
+ dlgX := x + 2; dlgY := y + 2; dlgInputX := x + 18;
|
|
|
+ dlgBtnX := x + 2; dlgBtnY := y + h - 2;
|
|
|
+ dlgCount := 0
|
|
|
+END Dialog;
|
|
|
+
|
|
|
+PROCEDURE DlgLabel (text : ARRAY OF CHAR);
|
|
|
+ VAR v : ViewPtr;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN END;
|
|
|
+ v := NewView(VText, dlgX, dlgY, dlgW - 4, 1);
|
|
|
+ SetText(v, text);
|
|
|
+ AddView(dlg, v);
|
|
|
+ dlgY := dlgY + 1
|
|
|
+END DlgLabel;
|
|
|
+
|
|
|
+PROCEDURE DlgInput (label : ARRAY OF CHAR; initial : ARRAY OF CHAR) : INTEGER;
|
|
|
+ VAR lv : ViewPtr; iw : INTEGER;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN -1 END;
|
|
|
+ IF TextLen(label) > 0 THEN
|
|
|
+ lv := NewView(VText, dlgX, dlgY, dlgInputX - dlgX - 1, 1);
|
|
|
+ SetText(lv, label);
|
|
|
+ AddView(dlg, lv)
|
|
|
+ END;
|
|
|
+ iw := dlgWX + dlgW - 2 - dlgInputX;
|
|
|
+ IF iw < 8 THEN iw := 8 END;
|
|
|
+ IF NewDlgItem(VInput, dlgInputX, dlgY, iw, 1, initial) = NIL THEN END;
|
|
|
+ dlgY := dlgY + 2;
|
|
|
+ RETURN dlgCount - 1
|
|
|
+END DlgInput;
|
|
|
+
|
|
|
+PROCEDURE DlgCheck (label : ARRAY OF CHAR; checked : BOOLEAN) : INTEGER;
|
|
|
+ VAR v : ViewPtr; idx : INTEGER;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN -1 END;
|
|
|
+ v := NewDlgItem(VCheck, dlgX, dlgY, dlgW - 4, 1, label);
|
|
|
+ idx := dlgCount - 1;
|
|
|
+ IF (v # NIL) AND checked THEN v^.flags := v^.flags + vfSelected END;
|
|
|
+ dlgY := dlgY + 1;
|
|
|
+ RETURN idx
|
|
|
+END DlgCheck;
|
|
|
+
|
|
|
+PROCEDURE DlgRadio (label : ARRAY OF CHAR; selected : BOOLEAN) : INTEGER;
|
|
|
+ VAR v : ViewPtr; idx : INTEGER;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN -1 END;
|
|
|
+ v := NewDlgItem(VRadio, dlgX, dlgY, dlgW - 4, 1, label);
|
|
|
+ idx := dlgCount - 1;
|
|
|
+ IF (v # NIL) AND selected THEN v^.flags := v^.flags + vfSelected END;
|
|
|
+ dlgY := dlgY + 1;
|
|
|
+ RETURN idx
|
|
|
+END DlgRadio;
|
|
|
+
|
|
|
+PROCEDURE DlgButton (text : ARRAY OF CHAR; tag : INTEGER);
|
|
|
+ VAR v : ViewPtr; w : INTEGER;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN END;
|
|
|
+ w := TextLen(text) + 4;
|
|
|
+ v := NewView(VButton, dlgBtnX, dlgBtnY, w, 1);
|
|
|
+ SetText(v, text);
|
|
|
+ SetTag(v, tag);
|
|
|
+ AddView(dlg, v);
|
|
|
+ dlgBtnX := dlgBtnX + w + 2
|
|
|
+END DlgButton;
|
|
|
+
|
|
|
+PROCEDURE DlgTextAt (idx : INTEGER; VAR s : ARRAY OF CHAR);
|
|
|
+BEGIN
|
|
|
+ IF (idx >= 0) AND (idx < dlgCount) AND (dlgItems[idx]^.kind = VInput) THEN
|
|
|
+ CopyText(s, dlgItems[idx]^.text)
|
|
|
+ ELSE
|
|
|
+ s[0] := 0C
|
|
|
+ END
|
|
|
+END DlgTextAt;
|
|
|
+
|
|
|
+PROCEDURE DlgValue (idx : INTEGER) : INTEGER;
|
|
|
+BEGIN
|
|
|
+ IF (idx >= 0) AND (idx < dlgCount) AND
|
|
|
+ ((dlgItems[idx]^.flags DIV vfSelected) MOD 2 = 1) THEN
|
|
|
+ RETURN 1
|
|
|
+ END;
|
|
|
+ RETURN 0
|
|
|
+END DlgValue;
|
|
|
+
|
|
|
+PROCEDURE DlgRun () : INTEGER;
|
|
|
+ VAR e : Event; cmd : INTEGER; done : BOOLEAN; f : ViewPtr;
|
|
|
+BEGIN
|
|
|
+ IF dlg = NIL THEN RETURN cmCancel END;
|
|
|
+ AddView(desk, dlg);
|
|
|
+ BringToFront(dlg);
|
|
|
+ f := dlg^.first;
|
|
|
+ WHILE (f # NIL) AND (NOT IsFocusable(f)) DO f := f^.next END;
|
|
|
+ IF f # NIL THEN FocusView(f) END;
|
|
|
+ modal := dlg;
|
|
|
+ done := FALSE; cmd := cmNone;
|
|
|
WHILE NOT done DO
|
|
|
Finish;
|
|
|
- cmd := cmNone;
|
|
|
IF ReadEvent(e) THEN
|
|
|
- IF e.kind = evKey THEN
|
|
|
- IF e.key = kEsc THEN cmd := cmOK END
|
|
|
- END;
|
|
|
- IF cmd = cmNone THEN cmd := HandleEvent(e) END
|
|
|
- END;
|
|
|
- IF (cmd = cmOK) OR (cmd = cmClose) THEN done := TRUE END
|
|
|
+ IF (e.kind = evKey) AND (e.key = kEsc) THEN
|
|
|
+ cmd := cmCancel; done := TRUE
|
|
|
+ ELSE
|
|
|
+ cmd := HandleEvent(e);
|
|
|
+ IF cmd # cmNone THEN done := TRUE END
|
|
|
+ END
|
|
|
+ END
|
|
|
END;
|
|
|
modal := NIL;
|
|
|
- DelView(w)
|
|
|
+ DelView(dlg);
|
|
|
+ dlg := NIL;
|
|
|
+ RETURN cmd
|
|
|
+END DlgRun;
|
|
|
+
|
|
|
+PROCEDURE MessageBox (title : ARRAY OF CHAR; text : ARRAY OF CHAR;
|
|
|
+ kind : INTEGER) : INTEGER;
|
|
|
+ VAR w, total, left : INTEGER; b1, b2 : ViewPtr;
|
|
|
+BEGIN
|
|
|
+ w := TextLen(text) + 6;
|
|
|
+ IF w < 30 THEN w := 30 END;
|
|
|
+ IF w > cols - 4 THEN w := cols - 4 END;
|
|
|
+ Dialog(title, w, 7);
|
|
|
+ DlgLabel(text);
|
|
|
+ b1 := NIL; b2 := NIL;
|
|
|
+ IF kind = mbOKCancel THEN
|
|
|
+ DlgButton("OK", cmOK); b1 := dlg^.last;
|
|
|
+ DlgButton("Cancel", cmCancel); b2 := dlg^.last
|
|
|
+ ELSIF kind = mbYesNo THEN
|
|
|
+ DlgButton("Yes", cmYes); b1 := dlg^.last;
|
|
|
+ DlgButton("No", cmNo); b2 := dlg^.last
|
|
|
+ ELSE
|
|
|
+ DlgButton("OK", cmOK); b1 := dlg^.last
|
|
|
+ END;
|
|
|
+ IF b1 # NIL THEN
|
|
|
+ IF b2 # NIL THEN total := b1^.rect.w + b2^.rect.w + 2
|
|
|
+ ELSE total := b1^.rect.w END;
|
|
|
+ left := dlgWX + (dlgW - total) DIV 2;
|
|
|
+ MoveViewBy(b1, left - b1^.rect.x, 0);
|
|
|
+ IF b2 # NIL THEN MoveViewBy(b2, left + b1^.rect.w + 2 - b2^.rect.x, 0) END
|
|
|
+ END;
|
|
|
+ RETURN DlgRun()
|
|
|
+END MessageBox;
|
|
|
+
|
|
|
+PROCEDURE Message (title : ARRAY OF CHAR; text : ARRAY OF CHAR);
|
|
|
+ VAR discard : INTEGER;
|
|
|
+BEGIN
|
|
|
+ discard := MessageBox(title, text, mbOK)
|
|
|
END Message;
|
|
|
|
|
|
END tv.
|