$R-,S-,D+,T+,F-,V+,B- Unit FeltEdit; Interface Uses Crt; CONST ToUpper = 1; ToLower = 2; NoInput = 4; TYPE CharSet = SET OF CHAR; CharSetPtr = ^CharSet; JustType = (LeftJ,CenterJ,RightJ); FeltStr = STRING[12]; PromptStr = STRING[30]; FeltStrArray = ARRAY [0..255] OF FeltStr; FeltType = (CharT, StrT, EnumT, BoolT, ByteT, IntT, WordT, LongT); EditPtr = ^EditRecord; EditRecord = RECORD x, y, len, xpos : BYTE; just : JustType; prompt : PromptStr; CASE ftype : FeltType OF CharT : (CharP : ^CHAR; oksetC : CharSetPtr; modeC : BYTE); StrT : (StrP : ^STRING; oksetS : CharSetPtr; modeS : BYTE); EnumT, BoolT : (EnumP : ^BYTE; EnumAntall : BYTE; EnumStr : ^FeltStrArray); ByteT : (ByteP : ^BYTE; ByteMin, ByteMax : LongInt); IntT : (IntP : ^INTEGER; IntMin, IntMax : LongInt); WordT : (WordP : ^WORD; WordMin, WordMax : LongInt); LongT : (LongP : ^LongInt; LongMin, LongMax : LongInt); END; CONST Eantall : WORD = 0; BoolStr : ARRAY [0..1] OF FeltStr = ('FALSE','TRUE'); NumericSet : CharSet = ['0'..'9','.','+','-']; InsertMode : BOOLEAN = FALSE; LastRecord : WORD = 0; FeltAttr : BYTE = 14; EditAttr : BYTE = 112; CONST EditChar : CHAR = #255; FUNCTION EditStr(VAR str: String; VAR xpos: BYTE; len, mode : BYTE; ok : CharSetPtr;just : JustType): BOOLEAN; FUNCTION Pad(st:String;len : INTEGER): String; FUNCTION Tstr(l : LongInt; len : INTEGER): String; PROCEDURE ShowOne(VAR e : EditRecord); PROCEDURE ShowAll; PROCEDURE EditOne(VAR e : EditRecord); PROCEDURE EditARecord(n : WORD); FUNCTION UpCase(ch : CHAR): CHAR; FUNCTION LoCase(ch : CHAR): CHAR; PROCEDURE MakeStr(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : String; okp : Pointer; mode : BYTE); PROCEDURE MakeChar(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : CHAR; okp : Pointer; mode : BYTE); PROCEDURE MakeEnum(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v ; antall : BYTE; VAR enum_ar); PROCEDURE MakeBool(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : BOOLEAN); PROCEDURE MakeByte(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : BYTE; min, max : BYTE); PROCEDURE MakeInt(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : INTEGER; min, max : INTEGER); PROCEDURE MakeWord(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : WORD; min, max : WORD); PROCEDURE MakeLong(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : LongInt; min, max : LongInt); PROCEDURE EditAllRecords; PROCEDURE EditVar(VAR v); (**************************************************************************) Implementation VAR ERec : ARRAY [0..255] OF EditPtr; CONST No_Upper : String[3] = ''; No_Lower : String[3] = ''; FUNCTION UpCase(ch : CHAR): CHAR; VAR p : INTEGER; BEGIN IF (ch >= 'a') AND (ch <= 'z') THEN ch := CHAR(BYTE(ch)-32) ELSE BEGIN p := Pos(ch,No_Lower); IF p > 0 THEN ch := No_Upper[p]; END; UpCase := ch; END; FUNCTION LoCase(ch : CHAR): CHAR; VAR p : INTEGER; BEGIN IF (ch >= 'A') AND (ch <= 'Z') THEN ch := CHAR(BYTE(ch)+32) ELSE BEGIN p := Pos(ch,No_Upper); IF p > 0 THEN ch := No_Lower[p]; END; LoCase := ch; END; PROCEDURE MakeStr(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : String; okp : Pointer; mode : BYTE); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := StrT; xpos := 1; just := pjust; StrP := Addr(v); oksetS := okp; modeS := mode; END; Inc(EAntall); END; PROCEDURE MakeChar(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : CHAR; okp : Pointer; mode : BYTE); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := CharT; xpos := 1; just := pjust; CharP := Addr(v); oksetC := okp; modeC := mode; END; Inc(EAntall); END; PROCEDURE MakeEnum(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v ; antall : BYTE; VAR enum_ar); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := EnumT; xpos := 1; just := pjust; EnumP := Addr(v); EnumAntall := antall; EnumStr := Addr(enum_ar); END; Inc(EAntall); END; PROCEDURE MakeBool(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : BOOLEAN); BEGIN MakeEnum(px,py,plen,pjust,prstr,v,2,BoolStr); END; PROCEDURE MakeByte(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : BYTE; min, max : BYTE); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := ByteT; xpos := 1; just := pjust; ByteP := Addr(v); ByteMin := min; ByteMax := max; END; Inc(EAntall); END; PROCEDURE MakeInt(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : INTEGER; min, max : INTEGER); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := IntT; xpos := 1; just := pjust; IntP := Addr(v); IntMin := min; IntMax := max; END; Inc(EAntall); END; PROCEDURE MakeWord(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : WORD; min, max : WORD); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := WordT; xpos := 1; just := pjust; WordP := Addr(v); WordMin := min; WordMax := max; END; Inc(EAntall); END; PROCEDURE MakeLong(px, py, plen : BYTE; pjust : JustType; prstr : PromptStr; VAR v : LongInt; min, max : LongInt); BEGIN New(ERec[EAntall]); WITH ERec[Eantall]^ DO BEGIN x := px; y := py; len := plen; prompt := prstr; ftype := LongT; xpos := 1; just := pjust; LongP := Addr(v); LongMin := min; LongMax := max; END; Inc(EAntall); END; FUNCTION Pad(st:String;len : INTEGER): String; BEGIN IF len < 0 THEN BEGIN len := Lo(-len); WHILE len > Length(st) DO st := ' ' + st; END ELSE IF len > 0 THEN BEGIN len := Lo(len); WHILE len > Length(st) DO st := st + ' '; END; Pad := st; END; (* FUNCTION Justify(st : String; len : BYTE; just : JustType): String; VAR front : BOOLEAN; BEGIN CASE just OF LeftJ : Justify := Pad(st,len); CenterJ : BEGIN front := FALSE; WHILE Length(st) < len DO BEGIN IF front THEN st := ' ' + st ELSE st := st + ' '; front := NOT front; END; Justify := st; END; RightJ : Justify := Pad(st,-len); END; END; *) FUNCTION Tstr(l : LongInt; len : INTEGER): String; VAR st : String; BEGIN Str(l:len,st); Tstr := st; END; FUNCTION Refresh(len: BYTE; just : JustType; st : String): INTEGER; VAR front, back, offs : INTEGER; BEGIN front := len - Length(st); IF front < 0 THEN front := 0; CASE just OF LeftJ : BEGIN back := front; front := 0; END; RightJ : back := 0; CenterJ : BEGIN back := (front+1) DIV 2; Dec(front,back); END; END; IF front > 0 THEN Write('':front); Write(st); IF back > 0 THEN Write('':back); Refresh := front; END; PROCEDURE ShowOne(VAR e : EditRecord); VAR i : WORD; l : LongInt; attr : BYTE; BEGIN attr := TextAttr; GotoXY(e.x,e.y); Write(e.prompt); TextAttr := FeltAttr; CASE e.ftype OF CharT : IF Refresh(e.len,e.just,e.CharP^) = 0 THEN ; StrT : IF Refresh(e.len,e.just,e.StrP^) = 0 THEN ; BoolT, EnumT : IF Refresh(e.len,e.just,e.EnumStr^[e.EnumP^]) = 0 THEN ; ByteT : IF Refresh(e.len,e.just,Tstr(e.ByteP^,1)) = 0 THEN ; IntT : IF Refresh(e.len,e.just,Tstr(e.IntP^,1)) = 0 THEN ; WordT : IF Refresh(e.len,e.just,Tstr(e.WordP^,1)) = 0 THEN ; LongT : IF Refresh(e.len,e.just,Tstr(e.LongP^,1)) = 0 THEN ; END; TextAttr := attr; END; PROCEDURE ShowAll; VAR i : WORD; BEGIN FOR i := 0 TO Eantall-1 DO ShowOne(ERec[i]^); END; FUNCTION EditStr(VAR str: String; VAR xpos: BYTE; len, mode : BYTE; ok : CharSetPtr;just : JustType): BOOLEAN; VAR sx, sy : BYTE; st : String; cok, ferdig, change, dirty : BOOLEAN; PROCEDURE Del1; BEGIN Delete(st,xpos,1); Dirty := TRUE; END; PROCEDURE RefreshStr; BEGIN GotoXY(sx,sy); GotoXY(sx+xpos+Refresh(len,just,st)-1,sy); Dirty := FALSE; END; BEGIN EditStr := FALSE; sx := WhereX; sy := WhereY; st := str; dirty := TRUE; ferdig := FALSE; IF xpos > Length(str)+1 THEN xpos := 1; REPEAT IF len <= 1 THEN xpos := 1; {IF Dirty THEN }RefreshStr; EditChar := ReadKey; CASE EditChar OF #0 : BEGIN EditChar := ReadKey; CASE Ord(EditChar) OF 68 : BEGIN st := str; RefreshStr; Exit; END; 71 : BEGIN xpos := 1; END; 72, 80 : ferdig := TRUE; 75 : IF xpos > 1 THEN Dec(xpos); 77 : IF xpos <= Length(st) THEN Inc(xpos); 79 : BEGIN xpos := Length(st)+1; END; 82 : InsertMode := NOT InsertMode; 83 : Del1; $75 : st[0] := Chr(xpos-1); {Ctrl-End} ELSE Exit; END; END; ^H : IF xpos > 1 THEN BEGIN Dec(xpos); Del1; END; ^M : ferdig := TRUE; ^[ : BEGIN change := st <> str; IF change THEN BEGIN st := str; xpos := 1; END; RefreshStr; IF NOT change THEN Exit; END; #0..#255 : BEGIN IF mode AND ToUpper <> 0 THEN EditChar := UpCase(EditChar) ELSE IF mode AND ToLower <> 0 THEN EditChar := LoCase(EditChar); cok := mode AND NoInput = 0; IF (ok <> NIL) AND cok THEN cok := EditChar IN ok^; IF cok THEN BEGIN IF InsertMode THEN BEGIN IF Length(st) < len THEN BEGIN Insert(EditChar,st,xpos); Inc(xpos); END; END ELSE BEGIN IF xpos <= len THEN BEGIN IF xpos > Length(st) THEN st := st + EditChar ELSE st[xpos] := EditChar; Inc(xpos); END; END; Dirty := TRUE; END; END; END; UNTIL ferdig; str := st; EditStr := TRUE; END; FUNCTION EditNum(VAR e : EditRecord): BOOLEAN; VAR feil, sx, sy : WORD; st : String; num : LongInt; BEGIN EditNum:= FALSE; sx := WhereX; sy := WhereY; CASE e.ftype OF ByteT : num := e.ByteP^; IntT : num := e.IntP^; WordT : num := e.WordP^; LongT : num := e.LongP^; END; REPEAT GotoXY(sx,sy); Str(num:1,st); e.xpos := 1; IF NOT EditStr(st,e.xpos,e.len,0,Addr(NumericSet),e.just) THEN Exit; Val(st,num,feil); IF feil = 0 THEN BEGIN feil := 1; IF num < e.LongMin THEN num := e.LongMin ELSE IF num > e.LongMax THEN num := e.LongMax ELSE feil := 0; END; UNTIL feil = 0; EditNum := TRUE; CASE e.ftype OF ByteT : e.ByteP^ := num; IntT : e.IntP^ := num; WordT : e.WordP^ := num; LongT : e.LongP^ := num; END; END; FUNCTION EditEnum(VAR en; max : WORD; len : BYTE; just : JustType; VAR enstr : FeltStrArray): BOOLEAN; VAR e : BYTE ABSOLUTE en; b : BYTE; sx, sy : WORD; BEGIN b := e; sx := WhereX; sy := WhereY; EditEnum := TRUE; REPEAT GotoXY(sx,sy); IF Refresh(len,just,enstr[b]) = 0 THEN ; GotoXY(sx,sy); EditChar := ReadKey; CASE EditChar OF #0 : BEGIN EditChar := ReadKey; CASE Ord(EditChar) OF 68 : BEGIN EditEnum := FALSE; Exit; END; 71 : b := 0; 72, 80 : BEGIN e := b; Exit; END; 75 : b := Succ(b) MOD max; 77 : b := Pred(b+max) MOD max; 79 : b := max-1; ELSE BEGIN e := b; Exit; END; END; END; ^M : BEGIN e := b; Exit; END; ^[ : IF e <> b THEN b := e ELSE BEGIN EditEnum := FALSE; Exit; END; ' ': b := Succ(b) MOD max; END; UNTIL FALSE; END; PROCEDURE EditOne(VAR e : EditRecord); VAR res : BOOLEAN; attr : BYTE; st : String; BEGIN attr := TextAttr; WITH e DO BEGIN GotoXY(x,y); Write(prompt); TextAttr := EditAttr; CASE ftype OF CharT : BEGIN st := CharP^; res := EditStr(st,xpos,len,modeC,oksetC,just); IF res AND (Length(st) = 1) THEN CharP^ := st[1]; END; StrT : res := EditStr(StrP^,xpos,len,modeS,oksetS,just); BoolT, EnumT : res := EditEnum(EnumP^,EnumAntall,len,just,EnumStr^); ByteT, IntT, WordT, LongT : res := EditNum(e); END; END; TextAttr := attr; ShowOne(e); END; PROCEDURE EditVar(VAR v); VAR i : INTEGER; BEGIN FOR i := 0 TO EAntall-1 DO BEGIN IF Addr(v) = Erec[i]^.StrP THEN EditOne(Erec[i]^); Inc(i); END; END; PROCEDURE EditARecord(n : WORD); BEGIN IF n < Eantall THEN EditOne(Erec[n]^); END; PROCEDURE EditAllRecords; BEGIN REPEAT EditARecord(LastRecord); Case EditChar OF #80 : LastRecord := Succ(LastRecord) MOD Eantall; #72 : LastRecord := Pred(LastRecord + Eantall) MOD Eantall; ELSE Exit; END; UNTIL EditChar = #27; END; END.