dos_compilers/Borland Turbo Pascal v6/DEMOS/TCALC/TCINPUT.PAS
2024-07-02 07:11:05 -07:00

334 lines
9.6 KiB
Plaintext

{ Copyright (c) 1989,90 by Borland International, Inc. }
unit TCInput;
{ Turbo Pascal 6.0 object-oriented example input routines.
This unit is used by TCALC.PAS.
See TCALC.DOC for an more information about this example.
}
{$S-}
interface
uses Crt, TCUtil, TCScreen, TCLStr;
const
LeftInputArrow = #17;
RightInputArrow = #16;
YesNo = 'Y/N';
LegalYesNo = ['Y', 'N'];
AllUpper = True;
NotUpper = False;
ErrNumberError1 = 'You must enter a number from ';
ErrNumberError2 = ' to ';
ErrColumnError1 = 'You must enter a column from ';
ErrColumnError2 = ' to ';
ErrCellError = 'You must enter a legal cell';
type
InputField = object
StartCol : ScreenColRange;
StopCol : Integer;
InputRow : Integer;
MaxInputLen : Word;
Quit : Boolean;
InputData : LStringPtr;
UCase : Boolean;
InputArea : ScreenArea;
constructor Init(C1 : ScreenColRange; C2 : Integer; R : Integer;
InitMaxInputLen : Word; InitUCase : Boolean);
destructor Done;
function GetQuit : Boolean;
procedure Edit(StartCursor : Word);
procedure ClearInput;
end;
function ReadString(Prompt : String; Len : Word;
var ESCPressed : Boolean) : String;
function GetLegalChar(Prompt : String; Legal : CharSet;
var ESCPressed : Boolean) : Char;
function GetYesNo(Prompt : String; var ESCPressed : Boolean) : Boolean;
function GetNumber(Prompt : String; Low, High : Longint;
var Result : Boolean) : Longint;
implementation
constructor InputField.Init(C1 : ScreenColRange; C2 : Integer; R : Integer;
InitMaxInputLen : Word; InitUCase : Boolean);
{ Sets up an input field }
begin
InputData := New(LStringPtr, Init);
if InputData = nil then
Fail;
StartCol := C1;
StopCol := C2;
InputRow := R;
if InitMaxInputLen = 0 then
MaxInputLen := 65521 { Maximum area that a pointer can allocate }
else
MaxInputLen := InitMaxInputLen;
UCase := InitUCase;
Quit := False;
end; { InputField.Init }
destructor InputField.Done;
{ Remove memory used by an input field }
begin
Dispose(InputData, Done);
end; { InputField.Done }
function InputField.GetQuit : Boolean;
{ Check to see if an input field has been exited with ESC }
begin
GetQuit := Quit;
end; { InputField.GetQuit }
procedure InputField.Edit(StartCursor : Word);
{ Edits the input field }
var
CursorPos, Start, Cursor : Word;
Ch : Word;
Good, InsMode, Finished : Boolean;
R : ScreenRowRange;
SCol, ECol, EndCol : ScreenColRange;
begin
with InputData^ do
begin
Quit := False;
SCol := StartCol; { Figure out where the field starts and stops }
if StopCol <= 0 then
EndCol := Scr.CurrCols + StopCol
else
EndCol := StopCol;
if InputRow <= 0 then
R := Scr.CurrRows + InputRow
else
R := InputRow;
if (R = Scr.CurrRows) and (ECol = Scr.CurrCols) then
Dec(EndCol);
ECol := EndCol;
InputArea.Init(SCol, R, ECol, R, Colors.InputColor);
InputArea.Clear;
if StartCursor = 0 then
CursorPos := Succ(Length)
else
CursorPos := StartCursor;
Finished := False;
InsMode := True;
Cursor := Scr.InsCursor;
Start := Max(Longint(CursorPos) - ECol - SCol + 2, 1);
repeat
if CursorPos > Length then
ECol := EndCol;
if (CursorPos < Start) or (CursorPos > Start + ECol - SCol) then
Start := Max(Longint(CursorPos) - ECol + SCol, 1);
if (Start = 2) and (SCol <> StartCol) then
begin
SCol := StartCol;
Start := 1;
end;
if Start > 1 then
begin
if SCol = StartCol then
begin
Inc(Start);
SCol := Succ(StartCol); { Text is off left side of line }
end;
end
else
SCol := StartCol;
if Length > Start + ECol - SCol then
begin
if ECol = EndCol then
begin
if SCol <> StartCol then
Inc(Start);
ECol := Pred(EndCol); { Text is off right side of line }
end;
end
else
ECol := EndCol;
GotoXY(StartCol, R);
if SCol <> StartCol then { Text is off left side of line }
WriteColor(LeftInputArrow, Colors.InputArrowColor);
WriteColor(LeftJustStr(InputData^.Copy(Start, Succ(ECol - SCol)),
Succ(ECol - SCol)), Colors.InputColor);
if ECol <> EndCol then { Text is off right side of line }
WriteColor(RightInputArrow, Colors.InputArrowColor);
GotoXY(CursorPos - Start + SCol, R);
SetCursor(Cursor);
Ch := GetKey;
SetCursor(NoCursor);
case Ch of
Ord(' ')..Ord('~') : begin
if not (InsMode and (Length = MaxInputLen)) then
begin
if UCase then
Ch := Ord(UpCase(Chr(Ch)));
if InsMode or (CursorPos > Length) then
Good := Insert(Chr(Ch), CursorPos)
else begin
Good := True;
Change(Chr(Ch), CursorPos);
end;
if Good then
Inc(CursorPos);
end;
end;
HomeKey : CursorPos := 1;
EndKey : CursorPos := Succ(Length);
BS : begin
if CursorPos > 1 then
begin
Delete(Pred(CursorPos), 1);
Dec(CursorPos);
end;
end;
DelKey : begin
if CursorPos <= Length then
Delete(CursorPos, 1);
end;
LeftKey : begin
if CursorPos > 1 then
Dec(CursorPos);
end;
RightKey : begin
if CursorPos <= Length then
Inc(CursorPos);
end;
InsKey : begin
InsMode := not InsMode;
if InsMode then
Cursor := Scr.InsCursor
else
Cursor := Scr.OldCursor;
end;
CtrlLeftKey : begin { Move back one word }
if (CursorPos > 1) and (Data^[CursorPos] <> ' ') then
Dec(CursorPos);
while (CursorPos > 1) and (Data^[CursorPos] = ' ') do
Dec(CursorPos);
while (CursorPos > 1) and (Data^[Pred(CursorPos)] <> ' ') do
Dec(CursorPos);
end;
CtrlRightKey : begin { Move forward one word }
while (CursorPos <= Length) and (Data^[CursorPos] <> ' ') do
Inc(CursorPos);
while (CursorPos <= Length) and (Data^[CursorPos] = ' ') do
Inc(CursorPos);
end;
ESC : begin
ClearInput;
Quit := True;
Finished := True;
end;
CR : Finished := True;
end; { case }
until Finished;
end; { with }
end; { InputField.Edit }
procedure InputField.ClearInput;
{ Makes the input field data a null long string }
var
Good : Boolean;
begin
Good := InputData^.FromString('');
end; { InputField.ClearInput }
function ReadString(Prompt : String; Len : Word;
var ESCPressed : Boolean) : String;
{ Read a string from the input area }
var
I : InputField;
begin
with I do
begin
if not Init(Length(Prompt) + 3, 0, -1, Len, NotUpper) then
begin
ESCPressed := True;
ReadString := '';
end;
WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor);
Edit(0);
ReadString := InputData^.ToString;
ESCPressed := GetQuit;
Done;
end; { with }
ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor);
end; { ReadString }
function GetLegalChar(Prompt : String; Legal : CharSet;
var ESCPressed : Boolean) : Char;
{ Read a chanracter from the input area, only reading certain ones }
var
Ch : Char;
begin
WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor);
Ch := GetKeyChar(Legal);
ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor);
GetLegalChar := Ch;
end; { GetLegalChar }
function GetYesNo(Prompt : String; var ESCPressed : Boolean) : Boolean;
{ Prints a "Yes/No" prompt, allowing the user to type Y or N to answer the
question }
var
Ch : Char;
begin
WriteXY(Prompt + ' (' + YesNo + ')?', 1, Pred(Scr.CurrRows),
Colors.PromptColor);
Ch := GetKeyChar(LegalYesNo);
ESCPressed := Ch = Chr(ESC);
ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor);
GetYesNo := Ch = 'Y';
end; { GetYesNo }
function GetNumber(Prompt : String; Low, High : Longint;
var Result : Boolean) : Longint;
{ Prompts for a numeric value within a certain range }
var
I : InputField;
S : String;
Error : Integer;
L : Longint;
begin
with I do
begin
if not Init(Length(Prompt) + 3, 0, -1,
Max(Length(NumToString(Low)),
Length(NumToString(High))), NotUpper) then
begin
Result := False;
GetNumber := 0;
Exit;
end;
WriteXY(Prompt + ': ', 1, Pred(Scr.CurrRows), Colors.PromptColor);
repeat
Edit(0);
S := InputData^.ToString;
if (not GetQuit) and (S <> '') then
begin
Val(S, L, Error);
Result := (Error = 0) and (L >= Low) and (L <= High);
if not Result then
Scr.PrintError(ErrNumberError1 + NumToString(Low) +
ErrNumberError2 + NumToString(High));
end
else begin
Result := False;
L := 0;
end;
until Result or (S = '');
Done;
end; { with }
ClrEOLXY(1, Pred(Scr.CurrRows), Colors.BlankColor);
GetNumber := L;
end; { GetNumber }
end.