493 lines
12 KiB
ObjectPascal
493 lines
12 KiB
ObjectPascal
|
{$I M_OPS.PAS}
|
|||
|
|
|||
|
Unit m_MenuBox;
|
|||
|
|
|||
|
Interface
|
|||
|
|
|||
|
Uses
|
|||
|
m_Types,
|
|||
|
m_Input,
|
|||
|
m_Output;
|
|||
|
|
|||
|
Type
|
|||
|
TMenuBox = Class
|
|||
|
Console : TOutput;
|
|||
|
Image : TConsoleImageRec;
|
|||
|
HideImage : ^TConsoleImageRec;
|
|||
|
FrameType : Byte;
|
|||
|
BoxAttr : Byte;
|
|||
|
Box3D : Boolean;
|
|||
|
BoxAttr2 : Byte;
|
|||
|
BoxAttr3 : Byte;
|
|||
|
BoxAttr4 : Byte;
|
|||
|
Shadow : Boolean;
|
|||
|
ShadowAttr : Byte;
|
|||
|
HeadAttr : Byte;
|
|||
|
HeadType : Byte;
|
|||
|
Header : String;
|
|||
|
WasOpened : Boolean;
|
|||
|
|
|||
|
Constructor Create (Var Screen: TOutput);
|
|||
|
Destructor Destroy; Override;
|
|||
|
Procedure Open (X1, Y1, X2, Y2: Byte);
|
|||
|
Procedure Close;
|
|||
|
Procedure Hide;
|
|||
|
Procedure Show;
|
|||
|
End;
|
|||
|
|
|||
|
TMenuListStatusProc = Procedure (Num: Word; Str: String);
|
|||
|
|
|||
|
TMenuListBoxRec = Record
|
|||
|
Name : String;
|
|||
|
Tagged : Byte; { 0 = false, 1 = true, 2 = never }
|
|||
|
End;
|
|||
|
|
|||
|
TMenuList = Class
|
|||
|
Screen : TOutput;
|
|||
|
List : Array[1..65535] of ^TMenuListBoxRec;
|
|||
|
Box : TMenuBox;
|
|||
|
InKey : TInput;
|
|||
|
HiAttr : Byte;
|
|||
|
LoAttr : Byte;
|
|||
|
PosBar : Boolean;
|
|||
|
Format : Byte;
|
|||
|
LoChars : String;
|
|||
|
HiChars : String;
|
|||
|
ExitCode : Char;
|
|||
|
Picked : Integer;
|
|||
|
TopPage : Integer;
|
|||
|
NoWindow : Boolean;
|
|||
|
ListMax : Integer;
|
|||
|
AllowTag : Boolean;
|
|||
|
TagChar : Char;
|
|||
|
TagKey : Char;
|
|||
|
TagPos : Byte;
|
|||
|
TagAttr : Byte;
|
|||
|
Marked : Word;
|
|||
|
StatusProc : TMenuListStatusProc;
|
|||
|
Width : Integer;
|
|||
|
Length : Integer;
|
|||
|
X1 : Byte;
|
|||
|
Y1 : Byte;
|
|||
|
NoInput : Boolean;
|
|||
|
|
|||
|
Constructor Create (Var S: TOutput);
|
|||
|
Destructor Destroy; Override;
|
|||
|
Procedure Open (BX1, BY1, BX2, BY2: Byte);
|
|||
|
Procedure Close;
|
|||
|
Procedure Add (Str: String; B: Byte);
|
|||
|
Procedure Get (Num: Word; Var Str: String; Var B: Boolean);
|
|||
|
Procedure SetStatusProc (P: TMenuListStatusProc);
|
|||
|
Procedure Clear;
|
|||
|
Procedure Delete (RecPos : Word);
|
|||
|
{ Procedure Focus (Num: Word);}
|
|||
|
Procedure Update;
|
|||
|
End;
|
|||
|
|
|||
|
Implementation
|
|||
|
|
|||
|
Uses
|
|||
|
m_Strings;
|
|||
|
|
|||
|
Constructor TMenuBox.Create (Var Screen: TOutput);
|
|||
|
Begin
|
|||
|
Inherited Create;
|
|||
|
|
|||
|
Console := Screen;
|
|||
|
Shadow := True;
|
|||
|
ShadowAttr := 0;
|
|||
|
Header := '';
|
|||
|
FrameType := 6;
|
|||
|
Box3D := True;
|
|||
|
BoxAttr := 15 + 7 * 16;
|
|||
|
BoxAttr2 := 8 + 7 * 16;
|
|||
|
BoxAttr3 := 15 + 7 * 16;
|
|||
|
BoxAttr4 := 8 + 7 * 16;
|
|||
|
HeadAttr := 15 + 1 * 16;
|
|||
|
HeadType := 0;
|
|||
|
HideImage := NIL;
|
|||
|
WasOpened := False;
|
|||
|
|
|||
|
FillChar(Image, SizeOf(TConsoleImageRec), 0);
|
|||
|
|
|||
|
Console.BufFlush;
|
|||
|
End;
|
|||
|
|
|||
|
Destructor TMenuBox.Destroy;
|
|||
|
Begin
|
|||
|
Inherited Destroy;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuBox.Open (X1, Y1, X2, Y2: Byte);
|
|||
|
Const
|
|||
|
BF : Array[1..8] of String[8] =
|
|||
|
('<27>Ŀ<EFBFBD><C4BF><EFBFBD><EFBFBD><EFBFBD>',
|
|||
|
'<27>ͻ<EFBFBD><CDBB><EFBFBD>ͼ',
|
|||
|
'<27>ķ<EFBFBD><C4B7><EFBFBD>Ľ',
|
|||
|
'<27><EFBFBD><CDB8><EFBFBD>;',
|
|||
|
'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',
|
|||
|
'<27><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>',
|
|||
|
' ',
|
|||
|
'.-.||`-''');
|
|||
|
Var
|
|||
|
A : Integer;
|
|||
|
B : Integer;
|
|||
|
Ch : Char;
|
|||
|
Begin
|
|||
|
If Not WasOpened Then
|
|||
|
If Shadow Then
|
|||
|
Console.GetScreenImage(X1, Y1, X2 + 2{3}, Y2 + 1, Image)
|
|||
|
Else
|
|||
|
Console.GetScreenImage(X1, Y1, X2, Y2, Image);
|
|||
|
|
|||
|
WasOpened := True;
|
|||
|
|
|||
|
B := X2 - X1 - 1;
|
|||
|
|
|||
|
If Not Box3D Then Begin
|
|||
|
BoxAttr2 := BoxAttr;
|
|||
|
BoxAttr3 := BoxAttr;
|
|||
|
BoxAttr4 := BoxAttr;
|
|||
|
End;
|
|||
|
|
|||
|
Console.WriteXY (X1, Y1, BoxAttr, BF[FrameType][1] + strRep(BF[FrameType][2], B));
|
|||
|
Console.WriteXY (X2, Y1, BoxAttr4, BF[FrameType][3]);
|
|||
|
|
|||
|
For A := Y1 + 1 To Y2 - 1 Do Begin
|
|||
|
Console.WriteXY (X1, A, BoxAttr, BF[FrameType][4] + strRep(' ', B));
|
|||
|
Console.WriteXY (X2, A, BoxAttr2, BF[FrameType][5]);
|
|||
|
End;
|
|||
|
|
|||
|
Console.WriteXY (X1, Y2, BoxAttr3, BF[FrameType][6]);
|
|||
|
Console.WriteXY (X1+1, Y2, BoxAttr2, strRep(BF[FrameType][7], B) + BF[FrameType][8]);
|
|||
|
|
|||
|
If Header <> '' Then
|
|||
|
Case HeadType of
|
|||
|
0 : Console.WriteXY (X1 + 1 + (B - Length(Header)) DIV 2, Y1, HeadAttr, Header);
|
|||
|
1 : Console.WriteXY (X1 + 1, Y1, HeadAttr, Header);
|
|||
|
2 : Console.WriteXY (X2 - Length(Header), Y1, HeadAttr, Header);
|
|||
|
End;
|
|||
|
|
|||
|
If Shadow Then Begin
|
|||
|
For A := Y1 + 1 to Y2 + 1 Do
|
|||
|
For B := X2 to X2 + 1 Do Begin
|
|||
|
Ch := Console.ReadCharXY(B, A);
|
|||
|
Console.WriteXY (B + 1, A, ShadowAttr, Ch);
|
|||
|
End;
|
|||
|
|
|||
|
A := Y2 + 1;
|
|||
|
For B := (X1 + 2) To (X2 + 2) Do Begin
|
|||
|
Ch := Console.ReadCharXY(B, A);
|
|||
|
Console.WriteXY (B, A, ShadowAttr, Ch);
|
|||
|
End;
|
|||
|
End;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuBox.Close;
|
|||
|
Begin
|
|||
|
If WasOpened Then Console.PutScreenImage(Image);
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuBox.Hide;
|
|||
|
Begin
|
|||
|
If Assigned(HideImage) Then FreeMem(HideImage, SizeOf(TConsoleImageRec));
|
|||
|
|
|||
|
GetMem (HideImage, SizeOf(TConsoleImageRec));
|
|||
|
|
|||
|
Console.GetScreenImage (Image.X1, Image.Y1, Image.X2, Image.Y2, HideImage^);
|
|||
|
Console.PutScreenImage (Image);
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuBox.Show;
|
|||
|
Begin
|
|||
|
If Assigned (HideImage) Then Begin
|
|||
|
Console.PutScreenImage(HideImage^);
|
|||
|
FreeMem (HideImage, SizeOf(TConsoleImageRec));
|
|||
|
HideImage := NIL;
|
|||
|
End;
|
|||
|
End;
|
|||
|
|
|||
|
Constructor TMenuList.Create (Var S: TOutput);
|
|||
|
Begin
|
|||
|
Inherited Create;
|
|||
|
|
|||
|
Screen := S;
|
|||
|
Box := TMenuBox.Create(S);
|
|||
|
InKey := TInput.Create;
|
|||
|
ListMax := 0;
|
|||
|
HiAttr := 15 + 1 * 16;
|
|||
|
LoAttr := 1 + 7 * 16;
|
|||
|
PosBar := True;
|
|||
|
Format := 0;
|
|||
|
LoChars := #13#27;
|
|||
|
HiChars := '';
|
|||
|
NoWindow := False;
|
|||
|
AllowTag := False;
|
|||
|
TagChar := '*';
|
|||
|
TagKey := #32;
|
|||
|
TagPos := 0;
|
|||
|
TagAttr := 15 + 7 * 16;
|
|||
|
Marked := 0;
|
|||
|
Picked := 1;
|
|||
|
NoInput := False;
|
|||
|
StatusProc := NIL;
|
|||
|
|
|||
|
Screen.BufFlush;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Clear;
|
|||
|
Var
|
|||
|
A : Word;
|
|||
|
Begin
|
|||
|
For A := 1 to ListMax Do Dispose(List[A]);
|
|||
|
ListMax := 0;
|
|||
|
Marked := 0;
|
|||
|
End;
|
|||
|
|
|||
|
(*
|
|||
|
Procedure TMenuList.Focus (Num: Word);
|
|||
|
Var
|
|||
|
NewPicked : Word;
|
|||
|
NewTopPage : Word;
|
|||
|
Count : Word;
|
|||
|
Begin
|
|||
|
If Num > ListMax Then Exit;
|
|||
|
|
|||
|
Picked := 1;
|
|||
|
ListMax :=
|
|||
|
|
|||
|
For Count := 1 to ListMax Do
|
|||
|
|
|||
|
If Picked < ListMax Then Inc (Picked);
|
|||
|
If Picked > TopPage + Length - 1 Then Inc (TopPage);
|
|||
|
End;
|
|||
|
*)
|
|||
|
|
|||
|
Procedure TMenuList.Delete (RecPos : Word);
|
|||
|
Var
|
|||
|
Count : Word;
|
|||
|
Begin
|
|||
|
If List[RecPos] <> NIL Then Begin
|
|||
|
Dispose (List[RecPos]);
|
|||
|
|
|||
|
For Count := RecPos To ListMax - 1 Do
|
|||
|
List[Count] := List[Count + 1];
|
|||
|
|
|||
|
Dec (ListMax);
|
|||
|
End;
|
|||
|
End;
|
|||
|
|
|||
|
Destructor TMenuList.Destroy;
|
|||
|
Begin
|
|||
|
Box.Free;
|
|||
|
InKey.Free;
|
|||
|
|
|||
|
Clear;
|
|||
|
|
|||
|
Inherited Destroy;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Update;
|
|||
|
Var
|
|||
|
A : LongInt;
|
|||
|
S : String;
|
|||
|
B : Integer;
|
|||
|
C : Integer;
|
|||
|
Begin
|
|||
|
For A := 0 to Length - 1 Do Begin
|
|||
|
C := TopPage + A;
|
|||
|
If C <= ListMax Then Begin
|
|||
|
S := ' ' + List[C]^.Name + ' ';
|
|||
|
Case Format of
|
|||
|
0 : S := strPadR (S, Width, ' ');
|
|||
|
1 : S := strPadL (S, Width, ' ');
|
|||
|
2 : S := strPadC (S, Width, ' ');
|
|||
|
End;
|
|||
|
End Else
|
|||
|
S := strRep(' ', Width);
|
|||
|
|
|||
|
If C = Picked Then B := HiAttr Else B := LoAttr;
|
|||
|
|
|||
|
Screen.WriteXY (X1 + 1, Y1 + 1 + A, B, S);
|
|||
|
If PosBar Then
|
|||
|
Screen.WriteXY (X1 + Width + 1, Y1 + 1 + A, Box.BoxAttr2, '<27>');
|
|||
|
|
|||
|
If AllowTag Then
|
|||
|
If (C <= ListMax) and (List[C]^.Tagged = 1) Then
|
|||
|
Screen.WriteXY (TagPos, Y1 + 1 + A, TagAttr, TagChar)
|
|||
|
Else
|
|||
|
Screen.WriteXY (TagPos, Y1 + 1 + A, TagAttr, ' ');
|
|||
|
End;
|
|||
|
|
|||
|
If PosBar Then
|
|||
|
If (ListMax > 0) and (Length > 0) Then Begin
|
|||
|
A := (Picked * Length) DIV ListMax;
|
|||
|
If Picked >= ListMax Then A := Pred(Length);
|
|||
|
If (A < 0) or (Picked = 1) Then A := 0;
|
|||
|
Screen.WriteXY (X1 + Width + 1, Y1 + 1 + A, Box.BoxAttr2, '<27>');
|
|||
|
End;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Open (BX1, BY1, BX2, BY2 : Byte);
|
|||
|
Var
|
|||
|
Ch : Char;
|
|||
|
A : Word;
|
|||
|
sPos : Word;
|
|||
|
ePos : Word;
|
|||
|
First : Boolean;
|
|||
|
Begin
|
|||
|
If Not NoWindow Then
|
|||
|
Box.Open (BX1, BY1, BX2, BY2);
|
|||
|
|
|||
|
X1 := BX1;
|
|||
|
Y1 := BY1;
|
|||
|
|
|||
|
If (Picked < TopPage) or (Picked < 1) or (Picked > ListMax) or (TopPage < 1) or (TopPage > ListMax) Then Begin
|
|||
|
Picked := 1;
|
|||
|
TopPage := 1;
|
|||
|
End;
|
|||
|
|
|||
|
Width := BX2 - X1 - 1;
|
|||
|
Length := BY2 - Y1 - 1;
|
|||
|
TagPos := X1 + 1;
|
|||
|
|
|||
|
If NoInput Then Exit;
|
|||
|
|
|||
|
Repeat
|
|||
|
Update;
|
|||
|
|
|||
|
If Assigned(StatusProc) Then
|
|||
|
If ListMax > 0 Then
|
|||
|
StatusProc(Picked, List[Picked]^.Name)
|
|||
|
Else
|
|||
|
StatusProc(Picked, '');
|
|||
|
|
|||
|
Ch := InKey.ReadKey;
|
|||
|
Case Ch of
|
|||
|
#00 : Begin
|
|||
|
Ch := InKey.ReadKey;
|
|||
|
Case Ch of
|
|||
|
#71 : Begin { home }
|
|||
|
Picked := 1;
|
|||
|
TopPage := 1;
|
|||
|
End;
|
|||
|
#72 : Begin { up arrow }
|
|||
|
If Picked > 1 Then Dec (Picked);
|
|||
|
If Picked < TopPage Then Dec (TopPage);
|
|||
|
End;
|
|||
|
#73 : Begin { page up }
|
|||
|
If Picked - Length > 1 Then Dec (Picked, Length) Else Picked := 1;
|
|||
|
If TopPage - Length < 1 Then TopPage := 1 Else Dec(TopPage, Length);
|
|||
|
End;
|
|||
|
#79 : Begin { end }
|
|||
|
If ListMax > Length Then TopPage := ListMax - Length + 1;
|
|||
|
Picked := ListMax;
|
|||
|
End;
|
|||
|
#80 : Begin { down arrow }
|
|||
|
If Picked < ListMax Then Inc (Picked);
|
|||
|
If Picked > TopPage + Length - 1 Then Inc (TopPage);
|
|||
|
End;
|
|||
|
#81 : If ListMax > 0 Then Begin { page down }
|
|||
|
If ListMax > Length Then Begin
|
|||
|
If Picked + Length > ListMax Then
|
|||
|
Picked := ListMax
|
|||
|
Else
|
|||
|
Inc (Picked, Length);
|
|||
|
Inc (TopPage, Length);
|
|||
|
If TopPage + Length > ListMax Then TopPage := ListMax - Length + 1;
|
|||
|
End Else Begin
|
|||
|
Picked := ListMax;
|
|||
|
End;
|
|||
|
End;
|
|||
|
Else
|
|||
|
If Pos(Ch, HiChars) > 0 Then Begin
|
|||
|
ExitCode := Ch;
|
|||
|
Exit;
|
|||
|
End;
|
|||
|
End;
|
|||
|
End;
|
|||
|
Else
|
|||
|
If AllowTag and (Ch = TagKey) and (List[Picked]^.Tagged <> 2) Then Begin
|
|||
|
If (List[Picked]^.Tagged = 1) Then Begin
|
|||
|
Dec (List[Picked]^.Tagged);
|
|||
|
Dec (Marked);
|
|||
|
End Else Begin
|
|||
|
List[Picked]^.Tagged := 1;
|
|||
|
Inc (Marked);
|
|||
|
End;
|
|||
|
If Picked < ListMax Then Inc (Picked);
|
|||
|
If Picked > TopPage + Length - 1 Then Inc (TopPage);
|
|||
|
End Else
|
|||
|
If Pos(Ch, LoChars) > 0 Then Begin
|
|||
|
ExitCode := Ch;
|
|||
|
Exit;
|
|||
|
End Else Begin
|
|||
|
Ch := UpCase(Ch);
|
|||
|
First := True;
|
|||
|
sPos := Picked + 1;
|
|||
|
ePos := ListMax;
|
|||
|
|
|||
|
If sPos > ListMax Then sPos := 1;
|
|||
|
|
|||
|
A := sPos;
|
|||
|
|
|||
|
While (A <= ePos) Do Begin
|
|||
|
If UpCase(List[A]^.Name[1]) = Ch Then Begin
|
|||
|
While A <> Picked Do Begin
|
|||
|
If Picked < A Then Begin
|
|||
|
If Picked < ListMax Then Inc (Picked);
|
|||
|
If Picked > TopPage + Length - 1 Then Inc (TopPage);
|
|||
|
End Else
|
|||
|
If Picked > A Then Begin
|
|||
|
If Picked > 1 Then Dec (Picked);
|
|||
|
If Picked < TopPage Then Dec (TopPage);
|
|||
|
End;
|
|||
|
End;
|
|||
|
Break;
|
|||
|
End;
|
|||
|
If (A = ListMax) and First Then Begin
|
|||
|
A := 0;
|
|||
|
sPos := 1;
|
|||
|
ePos := Picked - 1;
|
|||
|
First := False;
|
|||
|
End;
|
|||
|
|
|||
|
Inc (A);
|
|||
|
End;
|
|||
|
End;
|
|||
|
End;
|
|||
|
Until False;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Close;
|
|||
|
Begin
|
|||
|
If Not NoWindow Then Box.Close;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Add (Str : String; B : Byte);
|
|||
|
Begin
|
|||
|
Inc (ListMax);
|
|||
|
New (List[ListMax]);
|
|||
|
List[ListMax]^.Name := Str;
|
|||
|
List[ListMax]^.Tagged := B;
|
|||
|
|
|||
|
If B = 1 Then Inc(Marked);
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.Get (Num : Word; Var Str : String; Var B : Boolean);
|
|||
|
Begin
|
|||
|
Str := '';
|
|||
|
B := False;
|
|||
|
If Num <= ListMax Then Begin
|
|||
|
Str := List[Num]^.Name;
|
|||
|
B := List[Num]^.Tagged = 1;
|
|||
|
End;
|
|||
|
End;
|
|||
|
|
|||
|
Procedure TMenuList.SetStatusProc (P : TMenuListStatusProc);
|
|||
|
Begin
|
|||
|
StatusProc := P;
|
|||
|
End;
|
|||
|
|
|||
|
End.
|