home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
pascal
/
tplib21.zip
/
INSTALL.EXE
/
ENHCON.PAS
< prev
next >
Wrap
Pascal/Delphi Source File
|
1993-06-24
|
106KB
|
2,716 lines
(*
TURBO PASCAL LIBRARY 2.1
ENHCON unit: Enhanced console I/O routines
*)
UNIT ENHCON;
{$V-}
{$L CRTVDU}
{$L CRTKB}
INTERFACE
USES
DOS,CRT,STRINGS,TIME;
TYPE
CharSet = SET OF CHAR;
ConsoleStr = STRING[80];
SignalErrorProc = PROCEDURE(width: BYTE);
EditFormatRec = { Edit configuration record }
RECORD
Attribute: BYTE; { Text attr. for editing field }
StartChar,
EndChar: CHAR; { Start/end marker characters }
MarkerAttr: BYTE; { Text attribute for markers }
AllowChars, { Allowable chars. in string }
ExitKeys: CharSet; { Keys to end edit }
EditKey, { Key to start edit }
RestoreKey, { Key to restore original }
AbortKey: CHAR; { Key to abort edit }
NumFormat: STRING[12]; { Format for numeric fields }
SignalError: SignalErrorProc; { Called to report an error }
Flags: WORD; { General control flags }
END;
WindowStatus = (Undefined,Closed,Hidden,Open,Active);
WindowBorder = ARRAY[1..8] OF CHAR;
WindowJustify = (WJustLeft,WJustCenter,WJustRight);
WindowMovement = (WMoveLeft,WMoveRight,WMoveUp,WMoveDown);
WindowDefinition =
RECORD { Definition of window }
X1, Y1, X2, Y2: BYTE; { Absolute co-ordinates }
DefaultAttr: BYTE; { Text attr. when opening }
DefaultCrsrHide: BOOLEAN; { Default cursor hide status }
DefaultCrsrSize: WORD; { Default cursor size }
Border: WindowBorder; { Border characters }
BorderAttr: BYTE; { Border colors }
HdrText, FtrText: ConsoleStr; { Header/footer text }
HdrAttr, FtrAttr: BYTE; { Header/footer text colors }
HdrPos, FtrPos: WindowJustify; { Header/footer position }
Flags: BYTE; { User flags }
END;
HelpConfiguration =
RECORD
WindowID: BYTE; { Window no. for help system }
HelpFileName: ConsoleStr; { Name of help file }
X1, Y1, X2, Y2: BYTE; { Co-ordinates of help window }
NormalAttr, { Attribute for normal text }
IndexAttr, { Attribute for index words }
SelectAttr: BYTE; { Attribute for selected word }
Border: WindowBorder; { Border characters }
BorderAttr: BYTE; { Attribute for border }
HdrText, FtrText: ConsoleStr; { Header/footer text }
HdrPos, FtrPos: WindowJustify; { Position of header/footer }
HdrAttr, FtrAttr: BYTE; { Attribute for header/footer }
GeneralKey, { Key for general help index }
ContextKey, { Key for context help }
LastHelpKey, { Key for last help screen }
MoveWindowKey: CHAR; { Key for window movement }
Flags: BYTE; { User flags }
END;
HelpErrorProc = PROCEDURE(HErr: BYTE);
CONST
{ Flag constants for edit format records and window definitions }
{ Flags affecting string edits only }
EdFlagTrimL = $0001; { Trim leading blanks }
EdFlagTrimR = $0002; { Trim trailing blanks }
EdFlagPadL = $0004; { Pad with leading blanks }
EdFlagPadR = $0008; { Pad with trailing blanks }
EdFlagUpper = $0010; { Force to upper case }
{ Flags affecting all edits }
EdFlagFlushKB = $0100; { Flush keyboard buffer }
EdFlagInsert = $0200; { Set insert/overwrite mode for edit }
EdFlagForceIns = $0400; { Force insert toggle to required state }
EdFlagInsStat = $0800; { Use insert toggle status for mode }
EdFlagFirstClr = $1000; { First character clears field }
EdFlagEdKeyExit = $2000; { Allow edit key to terminate edit }
EdFlagHideCrsr = $4000; { Hide cursor before edit }
{ Values for Flags field in WindowDefinition }
WFlagClrOpen = $01; { Clear window when opening }
WFlagClrClose = $02; { Clear window when closing }
WFlagClrHide = $04; { Clear window when hiding }
WFlagRestore = $08; { Restore original screen when closed }
WFlagShowBrdr = $10; { Display border around window }
WFlagWriteBrdr = $20; { Allow writing on border }
{ Values for Flags field in HelpConfiguration }
HFlagPageText = $01; { Use text instead of page arrows }
HFlagPageInd = $02; { Show page up/down indication in footer }
HFlagTitle = $04; { Show section title in header }
{ Values for cursor-size selection }
WCrsrDefault = $FF00;
WCrsrLine = $FE00;
WCrsrBlock = $FD00;
{ Key value for scroll lock control of help window }
HMoveScroll = #$FF;
{ Common border definitions }
WBorder1: WindowBorder =
(#218,#196,#191,#179,#217,#196,#192,#179); { Single line }
WBorder2: WindowBorder =
(#201,#205,#187,#186,#188,#205,#200,#186); { Double line }
WBorderV1H2: WindowBorder =
(#213,#205,#184,#179,#190,#205,#212,#179); { Horiz. double }
WBorderH1V2: WindowBorder =
(#214,#196,#183,#186,#189,#196,#211,#186); { Verticals double }
{ Text attributes for monochrome display (Add $80 for blinking) }
MonoNone = $00;
MonoUnderline = $01;
MonoNormal = $07;
MonoIntenseUL = $09;
MonoIntense = $0F;
MonoReverse = $70;
{ ASCII control codes }
NUL = #$00; { Null }
SOH = #$01; { Start Of Header }
STX = #$02; { Start of Text }
ETX = #$03; { End of Text }
EOT = #$04; { End Of Transmission }
ENQ = #$05; { Enquiry }
ACK = #$06; { Acknowledge }
BEL = #$07; { Bell }
BS = #$08; { Backspace }
HT = #$09; { Horizontal Tab }
LF = #$0A; { Line Feed }
VT = #$0B; { Vertical Tab }
FF = #$0C; { Form Feed }
CR = #$0D; { Carriage Return }
SO = #$0E; { Shift Out }
SI = #$0F; { Shift In }
DLE = #$10; { Data Link Escape }
DC1 = #$11; { Device Control 1 }
DC2 = #$12; { Device Control 2 }
DC3 = #$13; { Device Control 3 }
DC4 = #$14; { Device Control 4 }
NAK = #$15; { Negative Acknowledge }
SYN = #$16; { Synchronous idle }
ETB = #$17; { End Transmission Block }
CAN = #$18; { Cancel }
EM = #$19; { End of Medium }
SUB = #$1A; { Substitute }
ESC = #$1B; { Escape }
FS = #$1C; { File Separator }
GS = #$1D; { Group Separator }
RS = #$1E; { Record Separator }
US = #$1F; { Unit Separator }
DEL = #$7F; { Delete }
PoundSign = #$9C; { British pounds-sterling character }
StandardChars = [#32..#126]; { Set of printable, standard characters }
{ Extended keys - Values returned by ENHCON.ReadKey }
KeyIns = #$80;
KeyDel = #$81;
KeyUp = #$82;
KeyDown = #$83;
KeyLeft = #$84; KeyCLeft = #$8A;
KeyRight = #$85; KeyCRight = #$8B;
KeyHome = #$86; KeyCHome = #$8C;
KeyEnd = #$87; KeyCEnd = #$8D;
KeyPgUp = #$88; KeyCPgUp = #$8E;
KeyPgDn = #$89; KeyCPgDn = #$8F;
KeyA0 = #$90; KeyAHyphen = #$9A;
KeyA1 = #$91; KeyAEquals = #$9B;
KeyA2 = #$92;
KeyA3 = #$93;
KeyA4 = #$94; KeySTab = #$9D;
KeyA5 = #$95; KeyCPrtSc = #$9E;
KeyA6 = #$96;
KeyA7 = #$97;
KeyA8 = #$98;
KeyA9 = #$99;
KeyF1 = #$A0; KeySF1 = #$B0; KeyCF1 = #$C0; KeyAF1 = #$D0;
KeyF2 = #$A1; KeySF2 = #$B1; KeyCF2 = #$C1; KeyAF2 = #$D1;
KeyF3 = #$A2; KeySF3 = #$B2; KeyCF3 = #$C2; KeyAF3 = #$D2;
KeyF4 = #$A3; KeySF4 = #$B3; KeyCF4 = #$C3; KeyAF4 = #$D3;
KeyF5 = #$A4; KeySF5 = #$B4; KeyCF5 = #$C4; KeyAF5 = #$D4;
KeyF6 = #$A5; KeySF6 = #$B5; KeyCF6 = #$C5; KeyAF6 = #$D5;
KeyF7 = #$A6; KeySF7 = #$B6; KeyCF7 = #$C6; KeyAF7 = #$D6;
KeyF8 = #$A7; KeySF8 = #$B7; KeyCF8 = #$C7; KeyAF8 = #$D7;
KeyF9 = #$A8; KeySF9 = #$B8; KeyCF9 = #$C8; KeyAF9 = #$D8;
KeyF10 = #$A9; KeySF10 = #$B9; KeyCF10 = #$C9; KeyAF10 = #$D9;
KeyAA = #$E1; KeyAP = #$F0;
KeyAB = #$E2; KeyAQ = #$F1;
KeyAC = #$E3; KeyAR = #$F2;
KeyAD = #$E4; KeyAS = #$F3;
KeyAE = #$E5; KeyAT = #$F4;
KeyAF = #$E6; KeyAU = #$F5;
KeyAG = #$E7; KeyAV = #$F6;
KeyAH = #$E8; KeyAW = #$F7;
KeyAI = #$E9; KeyAX = #$F8;
KeyAJ = #$EA; KeyAY = #$F9;
KeyAK = #$EB; KeyAZ = #$FA;
KeyAL = #$EC;
KeyAM = #$ED;
KeyAN = #$EE;
KeyAO = #$EF;
{ Error codes }
ConErrXY = $01; { Co-ordinates invalid }
ConErrBorderXY = $02; { Co-ordinates invalid when border used }
ConErrMove = $03; { Cannot move window in specified direction }
ConErrOpen = $04; { Window is open }
ConErrClosed = $05; { Window not open }
ConErrHidden = $06; { Window is hidden }
ConErrNotHidden = $07; { Window not hidden }
ConErrZero = $08; { Cannot use window zero }
ConErrDefined = $09; { Window already defined }
ConErrUndefined = $0A; { Window has not been defined }
ConErrReturn = $0B; { Cannot return to previous window }
ConErrHeap = $10; { No heap store available }
ConErrHelpRead = $11; { Error reading from help file }
ConErrHelpInit = $12; { Help system already initialized }
ConErrNoHelpFile = $13; { Can't find/open specified help file }
ConErrHelpFormat = $14; { Format error in help file }
ConErrHelpIndex = $15; { Index entry invalid for specified window }
ConErrHelpInvalid = $16; { Help/window definition invalid }
ConErrHelpStkFull = $17; { Context stack overflow }
ConErrHelpStkEmpty = $18; { Context stack empty }
{ General control variables }
InsKeyEnable: BOOLEAN = FALSE; { Ins key mode select }
CursorInsert: BOOLEAN = FALSE; { Change cursor size flag }
WindowCheck: BOOLEAN = TRUE; { Control internal error checking }
EnhConHaltError: WORD = 0; { Code for halt on error }
HelpContext: BYTE = 0; { Section for context-sens. help }
VAR
HelpError: HelpErrorProc; { Address of help error handler }
FUNCTION ColorDisplay: BOOLEAN;
FUNCTION MaxCursorSize: BYTE;
PROCEDURE SetCursor(size: WORD);
FUNCTION GetCursor: WORD;
PROCEDURE HideCursor(hide: BOOLEAN);
FUNCTION CursorHidden: BOOLEAN;
PROCEDURE OrigCursor;
PROCEDURE LineCursor;
PROCEDURE BlockCursor;
FUNCTION GetDisplayPage: BYTE;
FUNCTION GetDisplayBase: WORD;
PROCEDURE GetMaxXY(VAR x,y: BYTE);
PROCEDURE FlushKB;
FUNCTION CapsLock: BOOLEAN;
FUNCTION NumLock: BOOLEAN;
FUNCTION ScrollLock: BOOLEAN;
FUNCTION InsertLock: BOOLEAN;
PROCEDURE ForceInsert(Ins: BOOLEAN);
PROCEDURE StdSignalError(width: BYTE);
FUNCTION EditString(form: EditFormatRec; VAR s: STRING; width: BYTE): CHAR;
FUNCTION EditInt(form: EditFormatRec; VAR i: LongInt; min,max: LongInt): CHAR;
FUNCTION EditReal(form: EditFormatRec; VAR r: REAL; min,max: REAL): CHAR;
FUNCTION EditDate(form: EditFormatRec; VAR Dt: DateRec): CHAR;
FUNCTION EditTime(form: EditFormatRec; VAR Tm: TimeRec): CHAR;
FUNCTION WindowResult: BYTE;
FUNCTION ConErrorMsg(ErrNum: BYTE): ConsoleStr;
PROCEDURE GetWindowDef(WindowID: BYTE; VAR d: WindowDefinition);
FUNCTION WindowStat(WindowID: BYTE): WindowStatus;
FUNCTION CurrentWindow: BYTE;
PROCEDURE DefineWindow(WindowID: BYTE; d: WindowDefinition);
PROCEDURE PurgeWindow(WindowID: BYTE);
PROCEDURE OpenWindow(WindowID: BYTE);
PROCEDURE SelectWindow(WindowID: BYTE);
PROCEDURE CloseWindow(WindowID: BYTE);
PROCEDURE HideWindow(WindowID: BYTE);
PROCEDURE ShowWindow(WindowID: BYTE);
PROCEDURE RelocateWindow(WindowID: BYTE; X,Y: BYTE);
PROCEDURE MoveWindow(WindowID: BYTE; Direction: WindowMovement);
PROCEDURE WriteWindow(s: ConsoleStr);
PROCEDURE HelpReset;
PROCEDURE PushHelpContext(NewContext: BYTE);
PROCEDURE PopHelpContext;
PROCEDURE HelpInitialize(h: HelpConfiguration);
PROCEDURE TextMode(Mode: WORD);
FUNCTION ReadKey: CHAR;
IMPLEMENTATION
TYPE
ScreenBlock = ARRAY[0..4000] OF WORD; { Access to screen store }
ScreenBlockPtr = ^ScreenBlock;
SysWindowDefinition = { System's window definition record (WDR) }
RECORD
U: WindowDefinition; { User's window defn. }
SavePosX, SavePosY: BYTE; { Saved cursor position }
SaveAttr: BYTE; { Saved text attribute }
SaveCrsrHide: BOOLEAN; { Saved crsr hide status }
SaveCrsrSize: WORD; { Saved cursor size }
SaveScreen: ScreenBlockPtr; { Pointer to saved screen }
PrevWindow: BYTE; { ID of previous window }
SysFlags: BYTE; { Flags for internal use }
END;
WindowRecPointer = ^SysWindowDefinition;
HelpIndexString = STRING[30]; { String to hold help index }
HelpStrPtr = ^ConsoleStr; { Used to build help section in store }
HelpRec = RECORD { Record format in help file }
CASE SecNum: BYTE OF
0: (SecOfs: LONGINT;
SecLength: WORD;
SecName: HelpIndexString);
1: (HelpText: ConsoleStr);
END;
CONST
BIOS_VIDEO = $10;
{ Keys used by edit routines }
EditKeys = [KeyLeft,KeyRight,KeyHome,KeyEnd,KeyDel,KeyIns,BS];
{ Conversion table for extended keys }
ExtKey: ARRAY[CHAR] OF CHAR =
(NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, KeySTab,
KeyAQ, KeyAW, KeyAE, KeyAR,
KeyAT, KeyAY, KeyAU, KeyAI,
KeyAO, KeyAP, NUL, NUL,
NUL, NUL, KeyAA, KeyAS,
KeyAD, KeyAF, KeyAG, KeyAH,
KeyAJ, KeyAK, KeyAL, NUL,
NUL, NUL, NUL, NUL,
KeyAZ, KeyAX, KeyAC, KeyAV,
KeyAB, KeyAN, KeyAM, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, KeyF1,
KeyF2, KeyF3, KeyF4, KeyF5,
KeyF6, KeyF7, KeyF8, KeyF9,
KeyF10, NUL, NUL, KeyHome,
KeyUp, KeyPgUp, NUL, KeyLeft,
NUL, KeyRight, NUL, KeyEnd,
KeyDown, KeyPgDn, KeyIns, KeyDel,
KeySF1, KeySF2, KeySF3, KeySF4,
KeySF5, KeySF6, KeySF7, KeySF8,
KeySF9, KeySF10, KeyCF1, KeyCF2,
KeyCF3, KeyCF4, KeyCF5, KeyCF6,
KeyCF7, KeyCF8, KeyCF9, KeyCF10,
KeyAF1, KeyAF2, KeyAF3, KeyAF4,
KeyAF5, KeyAF6, KeyAF7, KeyAF8,
KeyAF9, KeyAF10, KeyCPrtSc, KeyCLeft,
KeyCRight, KeyCEnd, KeyCPgDn, KeyCHome,
KeyA1, KeyA2, KeyA3, KeyA4,
KeyA5, KeyA6, KeyA7, KeyA8,
KeyA9, KeyA0, KeyAHyphen,KeyAEquals,
KeyCPgUp, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL,
NUL, NUL, NUL, NUL);
{ Date and time constants }
DateFieldSize = SizeOf(DateString)-1;
TimeFieldSize = SizeOf(TimeString)-1;
{ Values for SysFlags in WDR }
SysFlagOpen = $01; { Window is open }
SysFlagHidden = $02; { Window is hidden }
{ Initialized variables }
ErrorHalt: BOOLEAN = FALSE; { Signal to exit handler }
HelpInitialized: BOOLEAN = FALSE; { Set when help initialized }
HelpActive: BOOLEAN = FALSE; { Controls help access in ReadKey }
LastHelpSec: BYTE = 0; { Section number of last help }
ErrCode: BYTE = 0; { Holds result of last operation }
VAR
ExitSave: POINTER; { For use by exit procedure }
CGAcursor: BOOLEAN; { True if CGA cursor, false if MDA/EGA }
OrigCursorSize: WORD; { Size of cursor at start of program }
OrigCursorHide: BOOLEAN; { Hide/show status of cursor at start }
LineCrsr,
BlockCrsr: WORD; { Line/block cursors for current mode }
DisplayBase: WORD; { Holds base address of display store }
MaxScreenX, { Hold size of screen in columns/rows }
MaxScreenY: BYTE;
RoutineName: ConsoleStr; { Name of routine for error handler }
ActiveWindow: BYTE; { ID of currently active window }
WindowPtr: ARRAY[0..255] OF WindowRecPointer; { Pointers to WDRs }
HelpConfig: HelpConfiguration; { Current config. }
HelpFile: FILE OF HelpRec; { Help file }
HelpVar: HelpRec; { For access to file }
HelpIndexStr: ARRAY[1..255] OF HelpIndexString; { Holds index words }
HelpSectionOfs: ARRAY[1..255] OF LONGINT; { Offset to sec start }
HelpSectionLen: ARRAY[1..255] OF WORD; { Length of each sec }
MaxHelpSec: BYTE; { No. of highest sec }
HelpStore: ARRAY[1..1000] OF HelpStrPtr; { Ptrs to help buffer }
HelpStoreSize: WORD; { No. of recs in store }
IndexRows, { No. of rows for index }
IndexCols, { No. of cols.for index }
IndexColWidth: BYTE; { Width of index column }
HelpCtxStack: ARRAY[1..128] OF BYTE; { For push/pop of context }
HelpCtxIndex: BYTE; { Stack pointer }
FUNCTION GAcheck: BYTE; EXTERNAL;
{ Called during initialization. Returns 2 if EGA, 1 if VGA, 0 otherwise. }
{ Turns on CGA cursor emulation if VGA adapter is present }
PROCEDURE SetAbsCrsr(size: WORD); EXTERNAL;
FUNCTION ColorDisplay: BOOLEAN; EXTERNAL;
FUNCTION MaxCursorSize: BYTE; EXTERNAL;
PROCEDURE SetCursor(size: WORD);
BEGIN
IF size=WCrsrLine THEN { Check for line/block request }
SetAbsCrsr(LineCrsr)
ELSE
IF size=WCrsrBlock THEN
SetAbsCrsr(BlockCrsr)
ELSE
IF size<>WCrsrDefault THEN { Otherwise, set requested size }
SetAbsCrsr(size);
END;
FUNCTION GetCursor: WORD; EXTERNAL;
PROCEDURE HideCursor(hide: BOOLEAN); EXTERNAL;
FUNCTION CursorHidden: BOOLEAN; EXTERNAL;
PROCEDURE OrigCursor;
BEGIN
SetAbsCrsr(OrigCursorSize);
HideCursor(OrigCursorHide);
END;
PROCEDURE LineCursor;
BEGIN
SetAbsCrsr(LineCrsr);
END;
PROCEDURE BlockCursor;
BEGIN
SetAbsCrsr(BlockCrsr);
END;
FUNCTION ReadDisplay: WORD; EXTERNAL;
PROCEDURE WriteDisplay(CharAttr: WORD); EXTERNAL;
FUNCTION GetDisplayPage: BYTE; EXTERNAL;
FUNCTION GetDisplayBase: WORD;
BEGIN
GetDisplayBase:=DisplayBase;
END;
PROCEDURE GetMaxXY(VAR x,y: BYTE);
BEGIN
x:=MaxScreenX;
y:=MaxScreenY;
END;
PROCEDURE FlushKB; EXTERNAL;
FUNCTION CapsLock: BOOLEAN; EXTERNAL;
FUNCTION NumLock: BOOLEAN; EXTERNAL;
FUNCTION ScrollLock: BOOLEAN; EXTERNAL;
FUNCTION InsertLock: BOOLEAN; EXTERNAL;
PROCEDURE ForceInsert(Ins: BOOLEAN); EXTERNAL;
PROCEDURE StdSignalError(width: BYTE);
BEGIN
Write(BEL);
END;
FUNCTION EditString(form: EditFormatRec; VAR s: STRING; width: BYTE): CHAR;
{ Assumes that cursor is positioned at start of field upon entry.
Exits with cursor in same position. }
LABEL
GetNextKey; { Used in main editing loop }
VAR
SavedAttr: BYTE; { Saved text attribute }
SavedX,SavedY: BYTE; { Saved cursor position upon entry }
SavedStartCh,
SavedEndCh: WORD; { Saved character/attribute for markers }
SavedString: STRING; { Saved string (used by restore) }
SavedCursor: BOOLEAN; { Saved hide state of cursor }
Done, { Loop control variable }
FirstKey: BOOLEAN; { Cleared after first edit key pressed }
i: BYTE; { Index to string and temp. storage }
ch: CHAR; { User input }
PROCEDURE MoveCursor; { Move cursor to position i }
BEGIN
FirstKey:=FALSE; { Edit key has been pressed }
GotoXY(SavedX+i-1,SavedY);
END;
PROCEDURE ReWriteStr; { Update string on display }
BEGIN
GotoXY(SavedX,SavedY);
Write(PadR(s,width));
MoveCursor;
END;
FUNCTION InsertStat: BOOLEAN; { Return current insert mode }
BEGIN
WITH form DO
IF (Flags AND EdFlagInsStat)<>0 THEN
InsertStat:=InsertLock
ELSE
InsertStat:=(Flags AND EdFlagInsert)<>0;
END;
BEGIN { EditString }
SavedAttr:=TextAttr; { Save display status }
SavedX:=WhereX;
SavedY:=WhereY;
SavedCursor:=CursorHidden;
SavedString:=s; { Save original field contents }
WITH form DO
BEGIN
IF MarkerAttr=0 THEN { Use i to store marker attribute }
i:=TextAttr { Set to original if zero }
ELSE
i:=MarkerAttr;
IF Attribute<>0 THEN { Set field attr, if required }
TextAttr:=Attribute;
IF StartChar<>NUL THEN { Display start-of-field marker }
BEGIN
GotoXY(SavedX-1,SavedY);
SavedStartCh:=ReadDisplay;
WriteDisplay((i SHL 8)+ORD(StartChar));
END;
IF EndChar<>NUL THEN { Display end-of-field marker }
BEGIN
GotoXY(SavedX+width,SavedY);
SavedEndCh:=ReadDisplay;
WriteDisplay((i SHL 8)+ORD(EndChar));
END;
IF (Flags AND EdFlagForceIns)<>0 THEN
ForceInsert((Flags AND EdFlagInsert)<>0);
Done:=FALSE; { Set up loop }
i:=1; { Start at first character }
ReWriteStr; { Display current string in new attribute }
FirstKey:=TRUE; { No editing done yet }
IF (Flags AND EdFlagFlushKB)<>0 THEN
FlushKB; { Clear keyboard buffer if required }
REPEAT { Main editing loop }
IF (Flags AND EdFlagHideCrsr)<>0 THEN { Hide crsr if }
HideCursor(FirstKey); { 1st & enabled }
ch:=ReadKey;
IF (Flags AND EdFlagUpper)<>0 THEN { Force upper }
ch:=UpCase(ch);
IF ch IN AllowChars THEN { Add character }
BEGIN
IF FirstKey AND
((Flags AND EdFlagFirstClr)<>0) THEN
s:=''; { Clear field, if necessary }
IF InsertStat THEN { Insert mode }
BEGIN
IF LENGTH(s)=width THEN { Del if too long }
DELETE(s,width,1);
INSERT(ch,s,i); { Insert at crsr }
END
ELSE { Overwrite mode }
BEGIN
DELETE(s,i,1); { Replace char }
INSERT (ch,s,i);
END;
IF i<width THEN { Move forward unless at end }
INC(i);
ReWriteStr; { Update display }
END;
IF ch IN ExitKeys THEN { Chars to terminate edit }
BEGIN
IF NOT(ch IN EditKeys) OR
((Flags AND EdFlagEdKeyExit)<>0) OR FirstKey THEN
Done:=TRUE; { Only allow edit keys if 1st }
GOTO GetNextKey; { key or appropriate flag set }
END;
IF ch=EditKey THEN
BEGIN
FirstKey:=FALSE; { Disable "first clear" code }
GOTO GetNextKey;
END;
IF ch=AbortKey THEN
IF (AbortKey<>RestoreKey) OR FirstKey THEN
BEGIN { If abort key=restore key }
s:=SavedString; { only allow if first key }
i:=1;
Done:=TRUE; { Set flag to exit loop }
GOTO GetNextKey;
END;
IF ch=RestoreKey THEN
BEGIN
s:=SavedString; { Restore original string }
i:=1; { Move to first character }
ReWriteStr; { Update display }
FirstKey:=TRUE; { Reset "edited" flag }
GOTO GetNextKey;
END;
CASE ch OF { Check for all other keys }
KeyLeft: IF i>1 THEN
BEGIN
DEC(i);
MoveCursor;
END;
KeyRight: IF (i<width) AND (i<=LENGTH(s)) THEN
BEGIN
INC(i);
MoveCursor;
END;
KeyHome: BEGIN
i:=1;
MoveCursor;
END;
KeyEnd: BEGIN
IF LENGTH(s)<width THEN
i:=LENGTH(s)+1
ELSE
i:=LENGTH(s);
MoveCursor;
END;
KeyDel: BEGIN
DELETE(s,i,1);
ReWriteStr;
END;
BS: IF i>1 THEN
BEGIN
DEC(i);
IF InsertStat THEN
DELETE(s,i,1)
ELSE
s[i]:=' ';
ReWriteStr;
END;
END; { CASE ch }
GetNextKey:
UNTIL Done;
EditString:=ch; { Set return code }
IF (Flags AND EdFlagTrimL)<>0 THEN { Adjust string }
s:=TrimL(s);
IF (Flags AND EdFlagTrimR)<>0 THEN
s:=TrimR(s);
IF (Flags AND EdFlagPadL)<>0 THEN
s:=PadL(s,width);
IF (Flags AND EdFlagPadR)<>0 THEN
s:=PadR(s,width);
IF StartChar<>NUL THEN { Replace markers }
BEGIN
GotoXY(SavedX-1,SavedY);
WriteDisplay(SavedStartCh);
END;
IF EndChar<>NUL THEN
BEGIN
GotoXY(SavedX+width,SavedY);
WriteDisplay(SavedEndCh);
END;
TextAttr:=SavedAttr; { Update display in orig attribute }
i:=1;
ReWriteStr;
IF (Flags AND EdFlagHideCrsr)<>0 THEN { Restore cursor }
HideCursor(SavedCursor);
END; { WITH form }
END; { EditString }
FUNCTION EditInt(form: EditFormatRec; VAR i: LongInt; min,max: LongInt): CHAR;
VAR
SavedInt: LongInt; { Saved input integer }
SavedX, SavedY: BYTE; { Saved cursor position }
Done: BOOLEAN; { Loop control variable }
width, { Field width for edit }
decimals: BYTE; { Number of (assumed) decimal places }
ch: CHAR;
s: ConsoleStr;
x: INTEGER;
FUNCTION CalcAdjustment(d: BYTE): REAL; { Raise 10 to power d }
VAR
r: REAL;
k: BYTE;
BEGIN
IF d=0 THEN
CalcAdjustment:=1
ELSE
BEGIN
r:=10.0;
FOR k:=2 TO d DO
r:=r*10.0;
CalcAdjustment:=r;
END;
END;
BEGIN { EditInt }
Done:=FALSE;
SavedX:=WhereX;
SavedY:=WhereY;
SavedInt:=i;
WITH form DO
BEGIN
AllowChars:=['0'..'9', '+', '-', '.', ',', ' '];
s:=Format(1.0,NumFormat); { Determine field width and }
width:=LENGTH(s); { no. of (assumed) decimal places }
s:=Follow(s,'.');
s:=Span(s,DecDigits);
decimals:=LENGTH(s);
REPEAT
s:=Format(i/CalcAdjustment(decimals),NumFormat);
ch:=EditString(form,s,width); { Edit string rep. of no. }
x:=POS('-',s); { Check for negative no. }
IF x=0 THEN
x:=POS('(',s);
WITH FormatConfig DO { Remove signs & padding }
s:=Remove(s,CONCAT(' ,+-()*',Fill,Currency));
IF LENGTH(s)=0 THEN { Allow blank for zero }
s:='0';
IF x<>0 THEN { Prefix - sign if neg. }
s:=CONCAT('-',s);
IF POS('.',s)=0 THEN { Add decimal point }
s:=CONCAT(s,'.');
IF LENGTH(Follow(s,'.'))>decimals THEN
SignalError(width) { Check for excess dec. }
ELSE
BEGIN
s:=CONCAT(s,
DuplChar('0',decimals-LENGTH(Follow(s,'.'))));
DELETE(s,POS('.',s),1); { Add zeros/remove point }
VAL(s,i,x); { Convert back to number }
IF (x=0) AND (i>=min) AND (i<=max) THEN
Done:=TRUE { Exit loop if successful }
ELSE { else restore original }
BEGIN
SignalError(width);
i:=SavedInt;
END;
END;
UNTIL Done;
Write(Format(i/CalcAdjustment(decimals),NumFormat));
GotoXY(SavedX,SavedY); { Re-format }
EditInt:=ch;
END; { WITH form }
END; { EditInt }
FUNCTION EditReal(form: EditFormatRec; VAR r: REAL; min, max: REAL): CHAR;
LABEL
RepeatEdit;
VAR
SavedReal: REAL; { Saved input }
SavedX,SavedY: BYTE; { Saved cursor position }
Done: BOOLEAN; { Loop control variable }
width, { Field width for edit }
decimals: BYTE; { Number of decimal places }
ch: CHAR;
s: ConsoleStr;
x: INTEGER;
BEGIN { EditReal }
Done:=FALSE;
SavedX:=WhereX;
SavedY:=WhereY;
SavedReal:=r;
WITH form DO
BEGIN
s:=Format(1.0,NumFormat); { Determine field width and }
width:=LENGTH(s); { number of decimal places }
s:=Follow(s,'.');
s:=Span(s,DecDigits);
decimals:=LENGTH(s);
AllowChars:=['0'..'9', '+', '-', '.', ',', ' '];
IF decimals=0 THEN
AllowChars:=AllowChars+['E','e'];
REPEAT
IF decimals=0 THEN { Convert to string }
STR(r:width,s) { Use scientific if zero }
ELSE { decimals specified, else }
s:=Format(r,NumFormat); { standard formatting }
ch:=EditString(form,s,width); { Edit string rep. of no. }
s:=Remove(s,' ,');
IF decimals<>0 THEN
BEGIN
x:=POS('-',s); { Check for negative numbers }
IF x=0 THEN
x:=POS('(',s);
s:=Remove(s,CONCAT('+-()*$',PoundSign));
IF LENGTH(s)=0 THEN { Blank to zero }
s:='0';
IF x<>0 THEN { Add minus }
s:=CONCAT('-',s);
IF LENGTH(Follow(s,'.'))>decimals THEN
BEGIN { Check decimals }
SignalError(width);
GOTO RepeatEdit;
END;
END;
VAL(s,r,x); { Convert back }
IF (x=0) AND (r>=min) AND (r<=max) THEN
Done:=TRUE { If successful, exit loop }
ELSE { Otherwise, restore value }
BEGIN
SignalError(width);
r:=SavedReal;
END;
RepeatEdit:
UNTIL Done;
IF decimals=0 THEN
Write(r:width)
ELSE
Write(Format(r,NumFormat)); { Re-format display }
GotoXY(SavedX,SavedY);
EditReal:=ch;
END; { WITH form }
END; { EditReal }
FUNCTION EditDate(form: EditFormatRec; VAR Dt: DateRec): CHAR;
VAR
s1,s2: DateString;
ch: CHAR;
i,x,y: BYTE;
v: BOOLEAN;
BEGIN
WITH form DO { Build list of allowable characters }
BEGIN
AllowChars:=['0'..'9','A'..'Z','a'..'z'];
FOR i:=1 TO LENGTH(DateParseDelims) DO
AllowChars:=AllowChars+[DateParseDelims[i]];
AllowChars:=AllowChars-[HT];
END;
x:=WhereX; { Save cursor position }
y:=WhereY;
s1:=PadL(DateStr(Dt),DateFieldSize); { Convert date to string }
REPEAT
s2:=s1;
ch:=EditString(form,s2,DateFieldSize); { Edit string rep. }
v:=DateParse(s2,Dt); { Validate string & convert }
IF NOT(v) THEN { Signal error if invalid }
form.SignalError(DateFieldSize);
UNTIL v;
Write(PadL(DateStr(Dt),DateFieldSize));
GotoXY(x,y);
EditDate:=ch; { Return exit-key code }
END; { EditDate }
FUNCTION EditTime(form: EditFormatRec; VAR Tm: TimeRec): CHAR;
VAR
s1,s2: TimeString;
ch: CHAR;
i,x,y: BYTE;
v: BOOLEAN;
BEGIN
WITH form DO { Build list of allowable characters }
BEGIN
AllowChars:=['0'..'9','A','a','P','p','M','m'];
FOR i:=1 TO LENGTH(TimeParseDelims) DO
AllowChars:=AllowChars+[TimeParseDelims[i]];
AllowChars:=AllowChars-[HT];
END;
x:=WhereX; { Save cursor position }
y:=WhereY;
s1:=PadL(TimeStr(Tm),TimeFieldSize); { Convert time to string }
REPEAT
s2:=s1;
ch:=EditString(form,s2,TimeFieldSize); { Allow user to edit it }
v:=TimeParse(s2,Tm); { Validate string }
IF NOT(v) THEN { Signal error if invalid }
form.SignalError(TimeFieldSize);
UNTIL v;
Write(PadL(TimeStr(Tm),TimeFieldSize)); { Re-format display }
GotoXY(x,y);
EditTime:=ch; { Return exit-key code }
END; { EditTime }
FUNCTION WindowResult: BYTE; { Return last error code and reset to zero }
BEGIN
WindowResult:=ErrCode;
ErrCode:=0;
END;
FUNCTION ConErrorMsg(ErrNum: BYTE): ConsoleStr;
CONST
Msg: ARRAY[0..$18] OF ConsoleStr =
('Successful',
'Invalid co-ordinates',
'Invalid border co-ordinates',
'Invalid direction',
'Window is open',
'Window not open',
'Window is hidden',
'Window not hidden',
'Illegal window zero operation',
'Window already defined',
'Undefined window',
'Cannot return to previous window',
'Undefined error',
'Undefined error',
'Undefined error',
'Undefined error',
'Out of memory',
'Cannot access help file',
'Help system already initialized',
'Help file not found',
'Invalid format in help file',
'Invalid format for help index',
'Help record invalid',
'Help context stack overflow',
'Help context stack empty');
BEGIN
IF ErrNum<=$18 THEN
ConErrorMsg:=Msg[ErrNum]
ELSE
ConErrorMsg:='Undefined error';
END;
PROCEDURE WError(e: BYTE); { Set up a windows-unit error condition }
BEGIN
ErrCode:=e; { Store error code }
IF WindowCheck THEN { If internal checking is enabled }
BEGIN { signal windows error and terminate }
ErrorHalt:=TRUE;
HALT(EnhConHaltError);
END;
END;
{$F+}
PROCEDURE HError(e: BYTE); { Set up an error condition }
BEGIN
ErrCode:=e; { Store error code }
ErrorHalt:=TRUE;
HALT(EnhConHaltError);
END;
{$F-}
FUNCTION CalcScreenMem(X1,Y1,X2,Y2: BYTE): WORD;
{ Calculate size of heap store required to save area of screen }
BEGIN
CalcScreenMem:=(X2-X1+1)*(Y2-Y1+1)*2;
END;
PROCEDURE WriteScreen(X1,Y1,X2,Y2: BYTE; P: ScreenBlockPtr);
{ Store screen area to heap }
VAR
ScrStore: ScreenBlockPtr;
R: Registers;
HeapOfs: WORD;
i: WORD;
x,y,z: BYTE;
BEGIN
HeapOfs:=0;
IF DirectVideo AND NOT(CheckSnow) THEN { Access screen directly }
BEGIN
ScrStore:=PTR(GetDisplayBase,0);
FOR y:=Y1 TO Y2 DO { For each row }
BEGIN
i:=(y-1)*MaxScreenX; { Offset to start of row }
FOR x:=X1 TO X2 DO { Save each chr./attr. }
BEGIN
P^[HeapOfs]:=ScrStore^[i+(x-1)];
INC(HeapOfs);
END;
END;
END
ELSE { Use BIOS calls }
BEGIN
z:=GetDisplayPage;
R.BH:=z;
R.AH:=$03;
INTR(BIOS_VIDEO,R); { Get cursor position }
i:=R.DX;
FOR y:=Y1 TO Y2 DO { For each row and column }
FOR x:=X1 TO X2 DO
BEGIN
R.BH:=z; { Move cursor to position }
R.DH:=y-1;
R.DL:=x-1;
R.AH:=$02;
INTR(BIOS_VIDEO,R);
R.BH:=z;
R.AH:=$08;
INTR(BIOS_VIDEO,R); { Read character/attr }
P^[HeapOfs]:=R.AX;
INC(HeapOfs); { Store in heap block }
END;
R.BH:=z;
R.DX:=i;
R.AH:=$02;
INTR(BIOS_VIDEO,R); { Restore cursor location }
END;
END; { WriteScreen }
PROCEDURE ReadScreen(X1,Y1,X2,Y2: BYTE; P: ScreenBlockPtr);
{ Read screen area back from heap }
VAR
ScrStore: ScreenBlockPtr;
R: Registers;
HeapOfs: WORD;
i: WORD;
x,y,z: BYTE;
BEGIN
HeapOfs:=0;
IF DirectVideo AND NOT(CheckSnow) THEN { Access screen directly }
BEGIN
ScrStore:=PTR(GetDisplayBase,0);
FOR y:=Y1 TO Y2 DO { For each row }
BEGIN
i:=(y-1)*MaxScreenX; { Offset to start of row }
FOR x:=X1 TO X2 DO { Get each chr./attribute }
BEGIN
ScrStore^[i+(x-1)]:=P^[HeapOfs];
INC(HeapOfs);
END;
END;
END
ELSE { Use BIOS calls }
BEGIN
z:=GetDisplayPage;
R.BH:=z;
R.AH:=$03;
INTR(BIOS_VIDEO,R); { Save cursor position }
i:=R.DX;
FOR y:=Y1 TO Y2 DO { For each row and column }
FOR x:=X1 TO X2 DO
BEGIN
R.BH:=z; { Move cursor to position }
R.DH:=y-1;
R.DL:=x-1;
R.AH:=$02;
INTR(BIOS_VIDEO,R);
R.BH:=z;
R.CX:=1;
R.BL:=HI(P^[HeapOfs]);
R.AL:=LO(P^[HeapOfs]);
R.AH:=$09;
INTR(BIOS_VIDEO,R); { Write to screen store }
INC(HeapOfs);
END;
R.BH:=z;
R.DX:=i;
R.AH:=$02;
INTR(BIOS_VIDEO,R); { Restore original cursor location }
END;
END; { ReadScreen }
PROCEDURE GetWindowDef(WindowID: BYTE; VAR d: WindowDefinition);
BEGIN
RoutineName:='GetWindowDef';
ErrCode:=0;
IF WindowPtr[WindowID]=NIL THEN
WError(ConErrUndefined) { Window must be defined }
ELSE
d:=WindowPtr[WindowID]^.U;
END;
FUNCTION WindowStat(WindowID: BYTE): WindowStatus;
{ Return current status of specified window }
BEGIN
ErrCode:=0;
IF WindowPtr[WindowID]=NIL THEN
WindowStat:=Undefined
ELSE
WITH WindowPtr[WindowID]^ DO
IF (SysFlags AND SysFlagOpen)=0 THEN
WindowStat:=Closed
ELSE
IF (SysFlags AND SysFlagHidden)=0 THEN
WindowStat:=Open
ELSE
WindowStat:=Hidden;
IF WindowID=ActiveWindow THEN
WindowStat:=Active;
END;
FUNCTION CurrentWindow: BYTE;
BEGIN
ErrCode:=0;
CurrentWindow:=ActiveWindow;
END;
PROCEDURE DefineWindow(WindowID: BYTE; d: WindowDefinition);
BEGIN
RoutineName:='DefineWindow';
ErrCode:=0;
IF WindowID=0 THEN { Can't define window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]<>NIL THEN { Check for already defined }
BEGIN
WError(ConErrDefined);
EXIT;
END;
WITH d DO
BEGIN
IF (X1<1) OR (Y1<1) OR (X2>MaxScreenX) OR (Y2>MaxScreenY) OR
(X2<X1) OR (Y2<Y1) THEN
BEGIN
WError(ConErrXY); { Check for invalid co-ordinates }
EXIT;
END;
IF ((Flags AND WFlagShowBrdr)<>0) AND
(((X2-X1)<2) OR ((Y2-Y1)<2)) THEN
BEGIN
WError(ConErrBorderXY);
EXIT;
END;
END;
NEW(WindowPtr[WindowID]); { Allocate WDR on heap }
IF WindowPtr[WindowID]=NIL THEN
BEGIN
WError(ConErrHeap);
EXIT;
END;
WITH WindowPtr[WindowID]^ DO
BEGIN
U:=d; { Transfer user window into WDR }
SaveScreen:=NIL; { No saved-screen block allocated }
SysFlags:=0; { Clear all system flags in WDR }
END;
END; { DefineWindow }
PROCEDURE PurgeWindow(WindowID: BYTE);
BEGIN
RoutineName:='PurgeWindow';
ErrCode:=0;
IF WindowID=0 THEN
BEGIN
WError(ConErrZero); { Can't purge window zero }
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN
BEGIN
WError(ConErrUndefined); { Window must be defined }
EXIT;
END;
IF (WindowPtr[WindowID]^.SysFlags AND SysFlagOpen)<>0 THEN
BEGIN
WError(ConErrOpen); { Window must be closed }
EXIT;
END;
DISPOSE(WindowPtr[WindowID]);
WindowPtr[WindowID]:=NIL;
END; { PurgeWindow }
PROCEDURE DrawBorder(d: WindowDefinition);
{ Draws border for window. Assumes window co-ordinates already set. }
VAR
i,p: BYTE;
a,b: BYTE;
s: ConsoleStr;
PROCEDURE WriteScrBIOS (ch: CHAR; count: WORD; x, y: BYTE);
{ Calls BIOS to write count copies of ch to screen using BorderAttr }
{ attribute and starting at cursor position x, y }
VAR
R: Registers;
BEGIN
GotoXY(x,y);
R.BH:=p;
R.AL:=ORD(ch);
R.BL:=d.BorderAttr;
R.CX:=count;
R.AH:=$09;
INTR(BIOS_VIDEO,R);
END;
BEGIN { DrawBorder }
p:=GetDisplayPage;
WITH d DO
BEGIN
a:=X2-X1+1;
b:=Y2-Y1+1;
WriteScrBIOS(Border[1],1,1,1); { Top left corner }
WriteScrBIOS(Border[3],1,a,1); { Top right corner }
WriteScrBIOS(Border[5],1,a,b); { Bottom right corner }
WriteScrBIOS(Border[7],1,1,b); { Bottom left corner }
FOR i:=2 TO (Y2-Y1) DO
BEGIN
WriteScrBIOS(Border[4],1,a,i); { Right-hand side }
WriteScrBIOS(Border[8],1,1,i); { Left-hand side }
END;
WriteScrBIOS(Border[2],a-2,2,1); { Top border }
WriteScrBIOS(Border[6],a-2,2,b); { Bottom border }
TextAttr:=HdrAttr; { Header text }
s:=TruncR(HdrText,a-2);
CASE HdrPos OF
WJustLeft: GotoXY(2,1);
WJustCenter: GotoXY((((a-2)-LENGTH(s)) DIV 2)+2,1);
WJustRight: GotoXY(a-LENGTH(s),1);
END;
WRITE(s);
TextAttr:=FtrAttr; { Footer text }
s:=TruncR(FtrText,a-2);
CASE FtrPos OF
WJustLeft: GotoXY(2,b);
WJustCenter: GotoXY((((a-2)-LENGTH(s)) DIV 2)+2,b);
WJustRight: GotoXY(a-LENGTH(s),b);
END;
WRITE(s);
END;
END; { DrawBorder }
PROCEDURE ClrScrArea(X1,Y1,X2,Y2: BYTE; A: BYTE);
{ Clears screen area specified to attribute value in A }
{ Leaves window definition, attribute, and cursor position unchanged }
VAR
SaveA,SaveX1,SaveY1,SaveX2,SaveY2,SaveX,SaveY: BYTE;
BEGIN
SaveA:=TextAttr;
SaveX:=WhereX;
SaveY:=WhereY;
SaveX1:=LO(WindMin)+1; { Save current window co-ordinates and }
SaveY1:=HI(WindMin)+1; { cursor position }
SaveX2:=LO(WindMax)+1;
SaveY2:=HI(WindMax)+1;
WINDOW(X1,Y1,X2,Y2); { Set co-ordinates to window to clear }
TextAttr:=A;
ClrScr; { Clear window, then restore everything }
WINDOW(SaveX1,SaveY1,SaveX2,SaveY2);
GotoXY(SaveX,SaveY);
TextAttr:=SaveA;
END;
PROCEDURE OpenWindow(WindowID: BYTE);
BEGIN
RoutineName:='OpenWindow';
ErrCode:=0;
IF WindowID=0 THEN { Trap calls for window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN { Check that window is defined }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
IF (WindowPtr[WindowID]^.SysFlags AND SysFlagOpen)<>0 THEN
BEGIN
WError(ConErrOpen); { Check window not already open }
EXIT;
END;
WITH WindowPtr[ActiveWindow]^ DO { Save current window details }
BEGIN
SavePosX:=WhereX;
SavePosY:=WhereY;
SaveCrsrHide:=CursorHidden;
SaveCrsrSize:=GetCursor;
SaveAttr:=TextAttr;
END;
WITH WindowPtr[WindowID]^,U DO { Set up new window }
BEGIN
IF (Flags AND WFlagRestore)<>0 THEN
BEGIN { Save screen if necessary }
GETMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
IF SaveScreen=NIL THEN
BEGIN
WError(ConErrHeap);
EXIT;
END;
WriteScreen(X1,Y1,X2,Y2,SaveScreen);
END;
WINDOW(X1,Y1,X2,Y2); { Set new co-ordinates for window }
TextAttr:=DefaultAttr; { Set default cursor & text attr. }
SetCursor(DefaultCrsrSize);
HideCursor(DefaultCrsrHide);
IF (Flags AND WFlagClrOpen)<>0 THEN
CLRSCR; { Clear window if required }
IF (Flags AND WFlagShowBrdr)<>0 THEN
BEGIN { Draw border if required }
DrawBorder(WindowPtr[WindowID]^.U);
IF (Flags AND WFlagWriteBrdr)=0 THEN
WINDOW(X1+1,Y1+1,X2-1,Y2-1);
TextAttr:=DefaultAttr;
END;
PrevWindow:=ActiveWindow; { Save for close routine }
SysFlags:=SysFlagOpen; { Flag window as open }
END; { WITH WindowPtr[WindowID]^,U }
GotoXY(1,1);
ActiveWindow:=WindowID; { New window is now active }
END; { OpenWindow }
PROCEDURE SelectWindow(WindowID: BYTE);
BEGIN
RoutineName:='SelectWindow';
ErrCode:=0;
IF WindowPtr[WindowID]=NIL THEN { Check for window is defined }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
WITH WindowPtr[WindowID]^ DO
BEGIN
IF (SysFlags AND SysFlagOpen)=0 THEN
BEGIN { Check that window is open }
WError(ConErrClosed);
EXIT;
END;
IF (SysFlags AND SysFlagHidden)<>0 THEN
BEGIN { Check window is not hidden }
WError(ConErrHidden);
EXIT;
END;
END;
WITH WindowPtr[ActiveWindow]^ DO { Save current cursor & attr. }
BEGIN
SavePosX:=WhereX;
SavePosY:=WhereY;
SaveCrsrHide:=CursorHidden;
SaveCrsrSize:=GetCursor;
SaveAttr:=TextAttr;
END;
WITH WindowPtr[WindowID]^,U DO { Set up for new window }
BEGIN
IF ((Flags AND WFlagWriteBrdr)<>0) OR
((Flags AND WFlagShowBrdr)=0) THEN
WINDOW(X1,Y1,X2,Y2)
ELSE
WINDOW(X1+1,Y1+1,X2-1,Y2-1);
TextAttr:=SaveAttr;
HideCursor(SaveCrsrHide);
SetCursor(SaveCrsrSize);
GotoXY(SavePosX,SavePosY);
END;
ActiveWindow:=WindowID;
END; { SelectWindow }
PROCEDURE CloseWindow(WindowID: BYTE);
BEGIN
RoutineName:='CloseWindow';
ErrCode:=0;
IF WindowID=0 THEN { Can't close window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN { Can't close an undefined window }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
WITH WindowPtr[WindowID]^,U DO
BEGIN
IF (SysFlags AND SysFlagOpen)=0 THEN
BEGIN
WError(ConErrClosed); { Window must be open }
EXIT;
END;
{ If current, return to previous window }
IF WindowID=ActiveWindow THEN
IF WindowStat(PrevWindow)=Open THEN
SelectWindow(PrevWindow)
ELSE
BEGIN
WError(ConErrReturn);
EXIT;
END;
IF ((Flags AND WFlagClrClose)<>0) AND
((SysFlags AND SysFlagHidden)=0) THEN
ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
IF SaveScreen<>NIL THEN { Restore saved screen }
BEGIN
IF (SysFlags AND SysFlagHidden)=0 THEN
ReadScreen(X1,Y1,X2,Y2,SaveScreen);
FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
SaveScreen:=NIL;
END;
SysFlags:=0;
END;
END; { CloseWindow }
PROCEDURE HideWindow(WindowID: BYTE);
VAR
s: ScreenBlockPtr;
BEGIN
RoutineName:='HideWindow';
ErrCode:=0;
IF WindowID=0 THEN { Can't hide window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN
BEGIN
WError(ConErrUndefined); { Window must be defined }
EXIT;
END;
WITH WindowPtr[WindowID]^,U DO { Must be open and not hidden }
BEGIN
IF (SysFlags AND SysFlagOpen)=0 THEN
BEGIN
WError(ConErrClosed);
EXIT;
END;
IF (SysFlags AND SysFlagHidden)<>0 THEN
BEGIN
WError(ConErrHidden);
EXIT;
END;
GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2)); { Allocate block }
IF s=NIL THEN
BEGIN
WError(ConErrHeap); { Check for out-of-memory }
EXIT;
END;
IF WindowID=ActiveWindow THEN
SelectWindow(0); { Select window zero if active }
WriteScreen(X1,Y1,X2,Y2,s); { Save window contents on heap }
IF (Flags AND WFlagClrHide)<>0 THEN { Clear if required }
ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
IF SaveScreen<>NIL THEN
BEGIN
ReadScreen(X1,Y1,X2,Y2,SaveScreen);
FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
END;
SaveScreen:=s; { Set WDR ptr to saved window; set flag }
SysFlags:=SysFlags OR SysFlagHidden;
END;
END; { HideWindow }
PROCEDURE ShowWindow(WindowID: BYTE);
VAR
s: ScreenBlockPtr;
BEGIN
RoutineName:='ShowWindow';
ErrCode:=0;
IF WindowID=0 THEN { Not valid for window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN { Window must be defined }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
WITH WindowPtr[WindowID]^,U DO
BEGIN
IF (SysFlags AND SysFlagOpen)=0 THEN
BEGIN
WError(ConErrClosed); { Check that window is open }
EXIT;
END;
IF (SysFlags AND SysFlagHidden)=0 THEN
BEGIN
WError(ConErrNotHidden); { Check window is hidden }
EXIT;
END;
IF (Flags AND WFlagRestore)<>0 THEN { Save screen if required }
BEGIN
GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
IF s=NIL THEN
BEGIN
WError(ConErrHeap); { Check for out-of-memory }
EXIT;
END;
WriteScreen(X1,Y1,X2,Y2,s);
END
ELSE
s:=NIL;
ReadScreen(X1,Y1,X2,Y2,SaveScreen); { Restore window }
FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
SaveScreen:=s;
SysFlags:=SysFlags AND (NOT(SysFlagHidden));
END;
END; { ShowWindow }
PROCEDURE RelocateWindow(WindowID: BYTE; X, Y: BYTE);
VAR
WindowWidth,
WindowHeight: BYTE;
RelocateStat: WindowStatus;
s: ScreenBlockPtr;
PROCEDURE StoreNewXY;
{ Stores new top-left co-ordinates in specified WDR }
{ Adjusts bottom-right co-ordinates to keep window size the same }
BEGIN
WITH WindowPtr[WindowID]^,U DO
BEGIN
X1:=X;
Y1:=Y;
X2:=X+WindowWidth;
Y2:=Y+WindowHeight;
END;
END;
BEGIN { RelocateWindow }
RoutineName:='RelocateWindow';
ErrCode:=0;
IF WindowID=0 THEN { Can't relocate window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN { Window must be defined }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
WITH WindowPtr[WindowID]^,U DO { Calc. window size and check }
BEGIN
WindowWidth:=X2-X1;
WindowHeight:=Y2-Y1;
END;
IF (X<1) OR (Y<1) OR
((X+WindowWidth)>MaxScreenX) OR ((Y+WindowHeight)>MaxScreenY) THEN
BEGIN
WError(ConErrXY);
EXIT;
END;
RelocateStat:=WindowStat(WindowID);
IF RelocateStat<Open THEN { If closed/hidden, store new XY }
StoreNewXY
ELSE { If on-screen, remove it, store }
WITH WindowPtr[WindowID]^,U DO { new XY, then redisplay }
BEGIN
GETMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
IF s=NIL THEN
BEGIN
WError(ConErrHeap);
EXIT;
END;
WriteScreen(X1,Y1,X2,Y2,s);
IF (Flags AND WFlagClrHide)<>0 THEN
ClrScrArea(X1,Y1,X2,Y2,DefaultAttr);
IF SaveScreen<>NIL THEN
ReadScreen(X1,Y1,X2,Y2,SaveScreen);
StoreNewXY;
IF SaveScreen<>NIL THEN
WriteScreen(X1,Y1,X2,Y2,SaveScreen);
ReadScreen(X1,Y1,X2,Y2,s);
FREEMEM(s,CalcScreenMem(X1,Y1,X2,Y2));
IF RelocateStat=Active THEN
SelectWindow(WindowID);
END;
END; { RelocateWindow }
PROCEDURE MoveWindow(WindowID: BYTE; Direction: WindowMovement);
CONST
RtnName = 'MoveWindow';
VAR
x,y: BYTE;
SaveErrCheck: BOOLEAN;
BEGIN
RoutineName:=RtnName;
ErrCode:=0;
IF WindowID=0 THEN { Can't move window zero }
BEGIN
WError(ConErrZero);
EXIT;
END;
IF WindowPtr[WindowID]=NIL THEN { Window must be defined }
BEGIN
WError(ConErrUndefined);
EXIT;
END;
x:=0; { Error trap value }
WITH WindowPtr[WindowID]^,U DO
CASE Direction OF { Set new top-left co-ordinates }
WMoveLeft: IF X1>1 THEN
BEGIN
x:=X1-1;
y:=Y1;
END;
WMoveRight: IF X2<MaxScreenX THEN
BEGIN
x:=X1+1;
y:=Y1;
END;
WMoveUp: IF Y1>1 THEN
BEGIN
x:=X1;
y:=Y1-1;
END;
WMoveDown: IF Y2<MaxScreenY THEN
BEGIN
x:=X1;
y:=Y1+1;
END;
END; { CASE Direction }
IF x=0 THEN
BEGIN
WError(ConErrMove); { Check for move errors }
EXIT;
END;
SaveErrCheck:=WindowCheck; { Save WindowCheck and set false so }
WindowCheck:=FALSE; { RelocateWindow cannot cause error }
RelocateWindow(WindowID,x,y); { Call RelocateWindow to move window }
WindowCheck:=SaveErrCheck; { Restore setting of WindowCheck }
IF ErrCode<>0 THEN
BEGIN
RoutineName:=RtnName; { If failed, generate an error }
WError(ErrCode);
END;
END; { MoveWindow }
PROCEDURE WriteWindow(s: ConsoleStr);
VAR
i,j: BYTE;
k: WORD;
w: ScreenBlockPtr;
BEGIN
RoutineName:='WriteWindow';
ErrCode:=0;
s:=TruncR(s,LO(WindMax)-LO(WindMin)-WhereX+2); { Limit string length }
IF LENGTH(s)=0 THEN EXIT; { Trap null string }
GETMEM(w,LENGTH(s)*2); { Allocate heap }
IF w=NIL THEN
BEGIN
WError(ConErrHeap);
EXIT;
END;
k:=TextAttr SHL 8;
FOR i:=1 TO LENGTH(s) DO { Build in memory }
w^[i-1]:=ORD(s[i])+k;
i:=LO(WindMin)+WhereX;
j:=HI(WindMin)+WhereY;
ReadScreen(i,j,i+LENGTH(s)-1,j,w); { Read block & discard }
FREEMEM(w,LENGTH(s)*2);
END; { WriteWindow }
PROCEDURE DisposeAll;
{ Throws away all heap-allocated storage }
VAR
i: BYTE;
BEGIN
FOR i:=0 TO 255 DO { Look at each pointer }
IF WindowPtr[i]<>NIL THEN { If window is defined }
BEGIN
WITH WindowPtr[i]^,U DO { Dispose of screen block }
IF SaveScreen<>NIL THEN
FREEMEM(SaveScreen,CalcScreenMem(X1,Y1,X2,Y2));
DISPOSE(WindowPtr[i]); { Dispose of WDR }
WindowPtr[i]:=NIL;
END;
END;
PROCEDURE Initialize;
{ Called at start-up and after a call to TextMode }
VAR
i: BYTE;
BEGIN
RoutineName:='initialization code';
ErrCode:=0;
MaxScreenX:=LO(WindMax)+1; { Save max. screen co-ordinates }
MaxScreenY:=HI(WindMax)+1;
IF MaxScreenX=40 THEN { Calculate base address }
DisplayBase:=GetDisplayPage*$0080+$B000
ELSE
DisplayBase:=GetDisplayPage*$0100+$B000;
IF ColorDisplay THEN
DisplayBase:=DisplayBase+$0800;
CASE GAcheck OF { Check display adapter }
0: CGAcursor:=ColorDisplay;
1: CGAcursor:=TRUE;
2: CGAcursor:=FALSE;
END;
IF CGAcursor THEN { Set default cursor values }
BEGIN
LineCrsr:=$0607;
BlockCrsr:=$0107;
END
ELSE
BEGIN
LineCrsr:=$0B0C;
BlockCrsr:=$010C;
END;
OrigCursorSize:=GetCursor; { Store cursor size for exit }
OrigCursorHide:=CursorHidden;
FOR i:=1 TO 255 DO { Set all window pointers to nil }
WindowPtr[i]:=NIL;
NEW(WindowPtr[0]);
IF WindowPtr[0]=NIL THEN
BEGIN
WError(ConErrHeap);
EXIT;
END;
WITH WindowPtr[0]^ DO { Set up window-zero WDR }
BEGIN
WITH U DO
BEGIN
X1:=1;
Y1:=1;
X2:=MaxScreenX;
Y2:=MaxScreenY;
DefaultAttr:=TextAttr;
DefaultCrsrHide:=FALSE;
DefaultCrsrSize:=WCrsrDefault;
Flags:=0;
END;
SaveScreen:=NIL;
SysFlags:=SysFlagOpen;
END;
ClrScr;
ActiveWindow:=0; { Assume window zero active }
END; { Initialize }
{$F+}
PROCEDURE ExitRestore; { Unit's exit handler }
BEGIN
ExitProc:=ExitSave; { Restore exit chain pointer }
IF HelpInitialized THEN
HelpReset;
DisposeAll; { Throw away all WDRs }
WINDOW(1,1,MaxScreenX,MaxScreenY); { Screen to full size }
GotoXY(1,MaxScreenY);
OrigCursor;
IF ErrorHalt THEN { If exit due to error }
BEGIN { display an error message }
TextAttr:=MonoNormal;
WRITELN;
WRITELN('ENHCON unit run-time error ',HexStr(ErrCode,2));
WRITELN(ConErrorMsg(ErrCode),' in ',RoutineName);
END;
END;
{$F-}
PROCEDURE ClearHelpPointers;
{ Initialize all help storage pointers to nil }
VAR
k: WORD;
BEGIN
FOR k:=1 to 1000 DO
HelpStore[k]:=NIL;
END;
PROCEDURE DisposeHelpStore;
{ Disposes of dynamically allocated help store and resets pointers }
VAR
k: WORD;
BEGIN
FOR k:=1 TO 1000 DO
IF HelpStore[k]<>NIL THEN
BEGIN
DISPOSE(HelpStore[k]);
HelpStore[k]:=NIL;
END;
END;
PROCEDURE HelpReset;
VAR
SaveWindowCheck: BOOLEAN;
SaveRtnName: ConsoleStr;
SaveErrCode: BYTE;
i: BYTE;
BEGIN
SaveRtnName:=RoutineName;
SaveErrCode:=ErrCode;
{$I-}
CLOSE(HelpFile);
i:=IOResult;
{$I+}
DisposeHelpStore;
SaveWindowCheck:=WindowCheck;
WindowCheck:=FALSE;
WITH HelpConfig DO
BEGIN
CloseWindow(WindowID);
PurgeWindow(WindowID);
WindowID:=0;
END;
WindowCheck:=SaveWindowCheck;
HelpInitialized:=FALSE;
ErrCode:=SaveErrCode;
RoutineName:=SaveRtnName;
END;
PROCEDURE HelpRequest(ch: CHAR);
{ Activates help system. On entry ch must hold code for
GeneralKey, ContextKey, or LastHelpKey }
CONST
RtnName = 'HelpRequest';
VAR
i: BYTE;
UserOption: INTEGER;
SaveWindowCheck: BOOLEAN;
MoveHelp: BOOLEAN;
PROCEDURE UpdateHdr(SectionNum: BYTE);
{ Updates header to to reflect section name. Zero indicates index. }
VAR
s: ConsoleStr;
i: BYTE;
BEGIN
WITH HelpConfig DO
BEGIN
GotoXY(2,1); { Position cursor & set attribs. }
TextAttr:=BorderAttr;
WRITE(DuplChar(Border[2],X2-X1-1));
s:=HdrText; { Get header text }
IF (Flags AND HFlagTitle)<>0 THEN
IF SectionNum=0 THEN { Append section }
s:=CONCAT(s,'Index') { name or index }
ELSE
s:=CONCAT(s,HelpIndexStr[SectionNum]);
s:=TruncR(s,X2-X1-1);
i:=X2-X1+1; { Rewrite header on screen }
CASE HdrPos OF
WJustLeft: GotoXY(2,1);
WJustCenter: GotoXY((((i-2)-LENGTH(s)) DIV 2)+2,1);
WJustRight: GotoXY(i-LENGTH(s),1);
END;
TextAttr:=HdrAttr;
WRITE(s);
END;
END; { UpdateHdr }
PROCEDURE UpdateFtr (PgInd: BYTE);
{ Writes footer to window if required, showing PgUp/PgDn indicators }
{ 0=None, 1=PgUp, 2=PgDn, 3=PgUp/PgDn }
VAR
s: ConsoleStr;
i,j: BYTE;
BEGIN
WITH HelpConfig DO
BEGIN
GotoXY(2,Y2-Y1+1); { Position cursor & set attributes }
TextAttr:=BorderAttr;
WRITE(DuplChar(Border[6],X2-X1-1));
s:=FtrText; { User's text }
IF (Flags AND HFlagPageInd)<>0 THEN { Page indicators }
CASE (Flags AND HFlagPageText)*4+PgInd OF
1: s:=CONCAT(s,#24,#32);
2: s:=CONCAT(s,#32,#25);
3: s:=CONCAT(s,#24,#25);
5: s:=CONCAT(s,'PgUp');
6: s:=CONCAT(s,'PgDn');
7: s:=CONCAT(s,'PgUp/PgDn');
END;
IF (PgInd<>0) AND (LENGTH(FtrText)<>0) THEN
INSERT(#32,s,LENGTH(FtrText)+1);
s:=TruncR(s,X2-X1-1); { Calc. position of footer text }
i:=X2-X1+1;
j:=Y2-Y1+1;
CASE FtrPos OF
WJustLeft: GotoXY(2,j);
WJustCenter: GotoXY((((i-2)-LENGTH(s)) DIV 2)+2,j);
WJustRight: GotoXY(i-LENGTH(s),j);
END;
TextAttr:=FtrAttr;
WindowCheck:=FALSE;
WriteWindow(s); { Display footer }
WindowCheck:=SaveWindowCheck;
RoutineName:=RtnName;
IF WindowResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHeap);
EXIT;
END;
END; { WITH HelpConfig }
END; { UpdateFtr }
FUNCTION ShowSection (Section: BYTE): INTEGER;
{ Displays specified help section, allowing PgUp/PgDn keys to scroll text.
Returns 0 if exit due to general-help key, -1 if due to Escape. }
VAR
UserOption: CHAR; { Used to get user's response }
SLen: WORD; { Length of section }
k: WORD; { Top-of-window line counter }
i,j,w: BYTE;
s: ConsoleStr;
BEGIN { ShowSection }
MoveHelp:=FALSE;
WITH HelpConfig DO
BEGIN
UpdateHdr(Section); { Update header }
SLen:=HelpSectionLen[Section]; { Get length of section }
{$I-}
SEEK(HelpFile,HelpSectionOfs[Section]); { Position file }
{$I+}
IF IOResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpRead);
EXIT;
END;
FOR k:=1 TO SLen DO { Read section to heap }
BEGIN
{$I-}
READ(HelpFile,HelpVar);
{$I+}
IF IOResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpRead);
EXIT;
END;
HelpStore[k]^:=HelpVar.HelpText;
END;
i:=Y2-Y1-1; { Calc. no. of rows in area }
w:=X2-X1-1; { Calculate maximum line length }
k:=1; { Start at 1st rec.in section }
REPEAT
TextAttr:=NormalAttr;
FOR j:=0 TO (i-1) DO { Display help in window }
BEGIN
GotoXY(2,j+2); { Position cursor }
WindowCheck:=FALSE;
IF (k+j)>SLen THEN { Display help }
WriteWindow(DuplChar(#32,w))
ELSE
WriteWindow
(TruncR(PadR(HelpStore[k+j]^,80),w));
WindowCheck:=SaveWindowCheck;
RoutineName:=RtnName;
IF WindowResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHeap);
EXIT;
END;
END; { FOR j }
IF k>1 THEN { Determine whether PgUp/PgDn allowed }
j:=1 { update footer accordingly }
ELSE
j:=0;
IF (k+i)<=SLen THEN
j:=j+2;
UpdateFtr(j);
UserOption:=ReadKey;
CASE UserOption OF
KeyLeft,KeyRight,KeyUp,KeyDown:
IF (MoveHelp=TRUE) OR
((MoveWindowKey=HMoveScroll) AND
ScrollLock) THEN
BEGIN
WindowCheck:=FALSE;
CASE UserOption OF
KeyUp:
MoveWindow(WindowID,WMoveUp);
KeyDown:
MoveWindow(WindowID,WMoveDown);
KeyLeft:
MoveWindow(WindowID,WMoveLeft);
KeyRight:
MoveWindow(WindowID,
WMoveRight);
END;
j:=WindowResult;
WindowCheck:=SaveWindowCheck;
RoutineName:=RtnName;
IF (j<>0) AND (j<>ConErrMove) THEN
BEGIN
HelpReset;
IF j=ConErrHeap THEN
HelpError(ConErrHeap)
ELSE
HelpError
(ConErrHelpInvalid);
EXIT;
END;
END;
KeyPgUp:
IF k>1 THEN
k:=k-i;
KeyPgDn:
IF (k+i)<=SLen THEN
k:=k+i;
KeyHome:
k:=1;
KeyEnd:
WHILE (k+i)<=SLen DO
k:=k+i;
ESC:
ShowSection:=-1;
ELSE
IF UserOption=GeneralKey THEN
ShowSection:=0
ELSE
IF UserOption=MoveWindowKey THEN
MoveHelp:=NOT(MoveHelp);
END; { CASE UserOption }
UNTIL UserOption IN [GeneralKey,ESC];
END; { WITH HelpConfig }
LastHelpSec:=Section;
END; { ShowSection }
FUNCTION ShowIndex: INTEGER;
{ Display help index and allow user to select required section.
Returns section number of selected item or -1 if Escape. }
VAR
CrsrRow,
CrsrCol: BYTE;
i,j,k: BYTE;
UserOption: CHAR;
PROCEDURE DisplayEntry (Selected: BOOLEAN);
{ Display index entry using normal index or selected index attribute.
Uses CrsrRow/Col and top-of-window counter k to determine which
entry to use. }
VAR
i: BYTE;
BEGIN
IF Selected THEN { Set attributes }
TextAttr:=HelpConfig.SelectAttr
ELSE
TextAttr:=HelpConfig.IndexAttr;
GotoXY(((CrsrCol-1)*IndexColWidth)+2,CrsrRow+1);
i:=(CrsrCol-1)*IndexRows+(CrsrRow-1)+k;
IF i<=MaxHelpSec THEN { Display name }
WRITE(PadR(HelpIndexStr[i],IndexColWidth-2))
ELSE
BEGIN
TextAttr:=HelpConfig.NormalAttr;
WRITE(DuplChar(#32,IndexColWidth-2));
END;
END; { DisplayEntry }
PROCEDURE RedrawIndex; { Redraws current index page }
VAR
SaveRow,
SaveCol: BYTE;
i,j: BYTE;
BEGIN
SaveRow:=CrsrRow; { Save current row/column pointers }
SaveCol:=CrsrCol;
IF k>1 THEN { Check whether PgUp/PgDn required }
j:=1
ELSE
j:=0;
IF (IndexRows*IndexCols+k)<=MaxHelpSec THEN
j:=j+2;
UpdateFtr(j); { Display or remove PgUp/PgDn }
FOR i:=1 TO IndexCols DO
BEGIN { Redraw each entry within window }
CrsrCol:=i;
FOR j:=1 TO IndexRows DO
BEGIN
CrsrRow:=j;
DisplayEntry(FALSE);
END;
END;
CrsrRow:=SaveRow; { Restore original row/col pointers }
CrsrCol:=SaveCol;
END; { RedrawIndex }
PROCEDURE NextPage; { Move to next index page }
BEGIN
IF (IndexRows*IndexCols+k)<=MaxHelpSec THEN
BEGIN
k:=k+IndexRows*IndexCols;
RedrawIndex;
CrsrCol:=1;
CrsrRow:=1;
END;
END; { NextPage }
PROCEDURE PrevPage; { Move to previous index page }
BEGIN
IF k>1 THEN
BEGIN
k:=k-IndexRows*IndexCols;
RedrawIndex;
CrsrCol:=IndexCols;
CrsrRow:=IndexRows;
END;
END; { PrevPage }
PROCEDURE NextSection;
{ Move index highlight bar to next section, advance to
next page if necessary }
BEGIN
IF ((CrsrCol-1)*IndexRows+(CrsrRow-1)+k+1)<=MaxHelpSec THEN
BEGIN
INC(CrsrRow);
IF CrsrRow>IndexRows THEN
BEGIN
INC(CrsrCol);
CrsrRow:=1;
IF CrsrCol>IndexCols THEN
NextPage;
END;
END;
END;
PROCEDURE PrevSection;
{ Move index highlight bar to previous section, move to
previous page if necessary }
BEGIN
IF (CrsrCol>1) OR (CrsrRow>1) OR (k>1) THEN
BEGIN
DEC(CrsrRow);
IF CrsrRow=0 THEN
BEGIN
DEC(CrsrCol);
CrsrRow:=IndexRows;
IF CrsrCol=0 THEN
PrevPage;
END;
END;
END;
BEGIN { ShowIndex }
WITH HelpConfig DO { Clear help window }
BEGIN
TextAttr:=NormalAttr;
FOR i:=2 TO (Y2-Y1) DO
BEGIN
GotoXY(2,i);
WRITE(DuplChar(#32,X2-X1-1));
END;
END; { WITH HelpConfig }
k:=1; { Start at top of index }
CrsrCol:=1;
CrsrRow:=1; { Position cursor on first entry }
UpdateHdr(0); { Update header text }
RedrawIndex; { Display first page of index }
WITH HelpConfig DO
REPEAT
DisplayEntry(TRUE); { Highlight entry, get user's }
UserOption:=ReadKey; { option, restore entry to normal }
DisplayEntry(FALSE);
CASE UserOption OF
KeyUp,KeyDown,KeyLeft,KeyRight:
IF (MoveHelp=TRUE) OR
((MoveWindowKey=HMoveScroll) AND
ScrollLock) THEN
BEGIN
WindowCheck:=FALSE;
CASE UserOption OF
KeyUp:
MoveWindow(WindowID,WMoveUp);
KeyDown:
MoveWindow(WindowID,WMoveDown);
KeyLeft:
MoveWindow(WindowID,WMoveLeft);
KeyRight:
MoveWindow(WindowID,WMoveRight);
END;
j:=WindowResult;
RoutineName:=RtnName;
WindowCheck:=SaveWindowCheck;
IF (j<>0) AND (j<>ConErrMove) THEN
BEGIN
HelpReset;
IF j=ConErrHeap THEN
HelpError(ConErrHeap)
ELSE
HelpError(ConErrHelpInvalid);
EXIT;
END;
END
ELSE
CASE UserOption OF
KeyUp: PrevSection;
KeyDown: NextSection;
KeyLeft: IF CrsrCol>1 THEN
DEC(CrsrCol);
KeyRight:
IF (CrsrCol<IndexCols) AND
((CrsrCol*IndexRows+(CrsrRow-1)+k)
<=MaxHelpSec) THEN
INC(CrsrCol);
END;
KeyPgUp: PrevPage;
KeyPgDn: NextPage;
KeySTab: PrevSection;
HT: NextSection;
ESC: ShowIndex:=-1;
ELSE
IF UserOption IN [CR,ContextKey] THEN
ShowIndex:=(CrsrCol-1)*IndexRows+(CrsrRow-1)+k
ELSE
IF UserOption=LastHelpKey THEN
ShowIndex:=LastHelpSec;
END; { CASE UserOption }
UNTIL UserOption IN [ESC,CR,ContextKey,LastHelpKey];
END; { ShowIndex }
BEGIN { HelpRequest }
IF NOT (HelpInitialized) THEN { Skip if not initialized }
EXIT;
RoutineName:=RtnName;
ErrCode:=0;
SaveWindowCheck:=WindowCheck;
WindowCheck:=FALSE;
WITH HelpConfig DO { Open window }
BEGIN
OpenWindow(WindowID);
i:=WindowResult;
WindowCheck:=SaveWindowCheck;
RoutineName:=RtnName;
IF i=ConErrHeap THEN
BEGIN
HelpReset;
HelpError(ConErrHeap);
EXIT;
END;
IF i<>0 THEN
BEGIN
HelpReset;
RoutineName:=RtnName;
HelpError(ConErrHelpInvalid);
EXIT;
END;
IF ch=GeneralKey THEN { Check help key }
UserOption:=0;
IF ch=LastHelpKey THEN
UserOption:=LastHelpSec;
IF ch=ContextKey THEN
IF HelpContext<=MaxHelpSec THEN
UserOption:=HelpContext
ELSE
UserOption:=0;
REPEAT
IF UserOption=0 THEN { If section=0 show index }
UserOption:=ShowIndex
ELSE
UserOption:=ShowSection(UserOption);
IF NOT(HelpInitialized) THEN
EXIT;
UNTIL UserOption=-1; { Loop until Esc pressed }
WindowCheck:=FALSE; { Close help window }
CloseWindow(WindowID);
RoutineName:=RtnName;
WindowCheck:=SaveWindowCheck;
IF WindowResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpInvalid);
END;
END; { WITH HelpConfig }
END; { HelpRequest }
PROCEDURE PushHelpContext(NewContext: BYTE);
{ Store current context value on stack, set new context value }
BEGIN
RoutineName:='PushHelpContext';
IF NOT(HelpInitialized) THEN { Ignore request if not installed }
EXIT;
IF HelpCtxIndex<>0 THEN { Check for stack overflow }
BEGIN { Add existing value to stack }
HelpCtxStack[HelpCtxIndex]:=HelpContext;
DEC(HelpCtxIndex);
HelpContext:=NewContext;
ErrCode:=0;
END
ELSE
BEGIN { Report overflow error }
HelpReset;
HelpError(ConErrHelpStkFull);
END;
END;
PROCEDURE PopHelpContext;
{ Retrieve context value from stack }
BEGIN
RoutineName:='PopHelpContext';
IF NOT(HelpInitialized) THEN { Ignore if not installed }
EXIT;
IF HelpCtxIndex<>128 THEN { Check for empty stack }
BEGIN { Retrieve value from stack }
INC(HelpCtxIndex);
HelpContext:=HelpCtxStack[HelpCtxIndex];
END
ELSE
BEGIN { Report stack-empty error }
HelpReset;
HelpError(ConErrHelpStkEmpty);
END;
END;
PROCEDURE HelpInitialize(h: HelpConfiguration);
CONST
RtnName = 'HelpInitialize';
VAR
HelpWindow: WindowDefinition;
i: BYTE;
k: WORD;
SaveWindowCheck: BOOLEAN;
BEGIN
RoutineName:=RtnName;
ErrCode:=0;
IF HelpInitialized THEN { Check whether already initialized }
BEGIN
HelpError(ConErrHelpInit);
EXIT;
END;
WITH HelpWindow DO { Set up definition for help window }
BEGIN
X1:=h.X1;
Y1:=h.Y1;
X2:=h.X2;
Y2:=h.Y2;
DefaultAttr:=h.NormalAttr;
DefaultCrsrSize:=WCrsrDefault;
DefaultCrsrHide:=TRUE;
Border:=h.Border;
BorderAttr:=h.BorderAttr;
HdrText:='';
FtrText:='';
Flags:=WFlagClrOpen+WFlagRestore+WFlagShowBrdr+WFlagWriteBrdr;
END;
HelpConfig:=h;
SaveWindowCheck:=WindowCheck; { Define the help window }
WindowCheck:=FALSE;
DefineWindow(h.WindowID,HelpWindow);
i:=WindowResult;
WindowCheck:=SaveWindowCheck;
RoutineName:=RtnName;
IF i<>0 THEN
BEGIN
HelpError(i);
EXIT;
END;
ASSIGN(HelpFile,h.HelpFileName); { Open help file }
{$I-}
RESET(HelpFile);
{$I+}
IF IOResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrNoHelpFile);
EXIT;
END;
i:=0;
REPEAT { Build help index }
IF EOF(HelpFile) THEN
BEGIN { If EOF, file is in error }
HelpReset;
HelpError(ConErrHelpFormat);
EXIT;
END;
{$I-}
READ(HelpFile,HelpVar); { Get next record }
{$I+}
IF IOResult<>0 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpRead);
EXIT;
END;
WITH HelpVar DO
IF SecNum=0 THEN
BEGIN { If it is an index entry }
IF i=255 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpFormat);
EXIT;
END;
INC(i); { Increment array index }
HelpIndexStr[i]:=SecName; { Store index & }
HelpSectionOfs[i]:=SecOfs; { file offset }
HelpSectionLen[i]:=SecLength;
END;
UNTIL HelpVar.SecNum>0; { Repeat until end of index }
MaxHelpSec:=i;
IF i=0 THEN
BEGIN { Error if no index records found }
HelpReset;
HelpError(ConErrHelpFormat);
EXIT;
END;
HelpStoreSize:=0; { Determine largest section size }
IndexColWidth:=0; { and length of longest index entry }
FOR i:=1 to MaxHelpSec DO
BEGIN
IF HelpSectionLen[i]>HelpStoreSize THEN
HelpStoreSize:=HelpSectionLen[i];
IF LENGTH(HelpIndexStr[i])>IndexColWidth THEN
IndexColWidth:=LENGTH(HelpIndexStr[i]);
END;
IndexColWidth:=IndexColWidth+2;
WITH HelpConfig DO { Calc. shape/size of index display }
BEGIN
IndexCols:=(X2-X1-1) DIV IndexColWidth;
IndexRows:=Y2-Y1-1;
END;
IF IndexCols<1 THEN
BEGIN
HelpReset;
HelpError(ConErrHelpIndex);
EXIT;
END;
FOR k:=1 to HelpStoreSize DO { Allocate help storage space on heap }
BEGIN
NEW(HelpStore[k]);
IF HelpStore[k]=NIL THEN
BEGIN
HelpReset;
HelpError(ConErrHeap);
EXIT;
END;
END;
HelpCtxIndex:=128; { Initialize context stack }
HelpInitialized:=TRUE;
END; { HelpInitialize }
PROCEDURE TextMode(Mode: WORD);
{ Add ENHCON code for text mode changes }
BEGIN
HelpReset; { Reset help system }
DisposeAll; { Discard WDRs and saved screen areas }
CRT.TextMode(Mode); { Call CRT unit to switch modes }
Initialize; { Re-initialize ENHCON unit }
END;
FUNCTION ReadKey: CHAR;
{ Chained into CRT.ReadKey. Performs cursor size change and checks
for help requests. }
VAR
ch: CHAR;
BEGIN
REPEAT
REPEAT
IF CursorInsert THEN { If cursor-change enabled }
IF InsertLock THEN { set cursor to appropriate size }
BlockCursor
ELSE
LineCursor;
ch:=CRT.ReadKey; { Call regular ReadKey function }
UNTIL (ch<DEL) OR (ch=PoundSign);
IF ch=NUL THEN { Check for extended key }
ch:=ExtKey[CRT.ReadKey]; { If found, get scan & convert }
IF NOT(HelpActive) THEN { Check for help request key }
WITH HelpConfig DO
IF (ch IN [GeneralKey,ContextKey,LastHelpKey]) THEN
BEGIN
HelpActive:=TRUE;
HelpRequest(ch);
HelpActive:=FALSE;
ch:=NUL;
END;
UNTIL (InsKeyEnable OR (ch<>KeyIns)) AND (ch<>NUL);
ReadKey:=ch; { Try again if key invalid }
END; { ReadKey }
BEGIN { Unit initialization code }
ExitSave:=ExitProc; { Install exit procedure }
ExitProc:=@ExitRestore;
Initialize; { Initialize to current display mode }
HelpError:=HError; { Install error handler }
ClearHelpPointers; { Reset help system }
HelpConfig.WindowID:=0;
END.