< -->

{$G+,D-,E-,N+}
Unit ProgFace;
              INTERFACE
const
 Black  =      0;
 Blue   =      1;
 Green  =      2;
 Cyan   =      3;
 Red    =      4;
 Magenta  =    5;
 Brown  =      6;
 LightGray =   7;
 DarkGray  =    8;
 LightBlue =    9;
 LightGreen =  10;
 LightCyan  =  11;
 LightRed   =  12;
 LightMagenta= 13;
 Yellow   =    14;
 White   =     15;
 Blink   =    128;
type
   TWindow = record
     X0, Y0, Xr, Yr : Byte;
   end;
var
  WinAttr, WBorderAttr, WinHAttr, MnAttrK, MnAttrM,
  ButtAttr, ButtLight, ButtShadow                  : Byte;
  xt, yt : Byte;
  NSav : Word;
  Window : TWindow;
Function KeyPressed : Boolean;
Procedure Delay(V, W : Word);
Procedure ClrScr;
Procedure SetBorderChar(C : Char);
Function ReadKey : Char;
Procedure PutChr(C:Char; Col : Byte);
Procedure PutCursor(xx, yy : Byte);
Procedure SetButton(x, y, NLight : Byte; Text : String);
Procedure CursorOff;
Procedure CursorOn;
Procedure SetDelay(Max, Min : Word);
Procedure WriteLine(S : String; Attr : Byte);
Procedure SetAttr(Tx, BkTx : Byte; var Attr : Byte);
Procedure SaveTexBar(x1, y1, x2, y2 : Byte; P : Pointer);
Procedure RestoreTexBar(x1, y1, x2, y2 : Byte; P : Pointer);
Procedure SaveBar(xx1, yy1, xx2, yy2 : Byte);
Procedure SetWindow (X1,Y1,X2,Y2,Bord: Byte;
                      Header: String; Build: Boolean);
Procedure SetButtSize(l, z : Byte);
Procedure SetWindChar(Ch : Char);
Procedure ZZCursor;
Procedure NewLine;
Procedure DoMenuLine(x, y : Byte; KeyS, MenuS : String);
Procedure WriteCharXY(x, y, Attr : Byte; c : Char);
Procedure Border (X1,Y1,X2,Y2,Bord: Byte);
Procedure PutWindow(X1,Y1,X2,Y2,Bord: Byte;Header: String);
{Procedure WriteLn(S : String; z : Word);}
Procedure UndoMenu;
Procedure WindowSize(X1, Y1, X2, Y2 : Byte);
Procedure UnPackAttribute(Attr: Byte; var Text, Back: Byte);
Procedure ResetTimer;
Procedure RestoreScreen;
            IMPLEMENTATION
type
   MenuSave = record
     x1, y1, x2, y2, Attrib: Byte;
     PMS : Pointer;
   end;
   PTar = ^Tar;
   Tar = array[1..2400] of Word;
var
  i      : Word;
  TextSize : array[1..500] of MenuSave;
const
  BorderChar : Array [0..2, 1..6] of Char =
     ((#32,#32,#32,#32,#32,#32),
      (#218,#196,#191,#179,#192,#217),
      (#201,#205,#187,#186,#200,#188));
  ButtLen : Byte = 10;
  ButtW : Byte = 2;
  WindChar : Char = #32;
const
  PMin : Word  = 30000;
  PMax : Word = 0;
{~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
Procedure SetDelay(Max, Min : Word);
begin
  PMin := Min;
  PMax := Max;
end;
{-=-=-=-=-=-=-=-=-=-=-=-=-=}
Procedure Delay(V, W : Word); Assembler;
asm
  @1:
    mov      cx, Word Ptr V
    mov      dx, Word Ptr W
    mov      ah, $86
    int      $15
    jc       @1
end;
{----------------}
Procedure ResetTimer;Assembler;
asm
    mov      cx, 0
    mov      dx, 1
    mov      ah, $86
    int      $15
    jnc       @1
    mov ah, 83h
    mov al, 1
    int 15h
@1:
end;
{------------------------}
Function KeyPressed : Boolean;Assembler;
asm
 mov ah, $0B
 int $21
end;
{------------------------}
Procedure SetBorderChar(C : Char);
var
  i : Integer;
begin
  for i := 1 to 6 do
    BorderChar[0, i] := C;
end;
{------------------}
Procedure SetButton(x, y, NLight : Byte; Text : String);
var
  i, j : Byte;
begin
 if Length(Text) >= ButtLen then Text[0] := Char(ButtLen-1);
 for j := 1 to ButtW do
  begin
   if (j = ButtW div 2) then
   begin
     for i := 1 to ButtLen do
     begin
       if i<=Length(Text) then
         if i=NLight then
             WriteCharXY(x+i-1, y+j-1, ButtLight, Text[i])
         else
             WriteCharXY(x+i-1, y+j-1, ButtAttr , Text[i])
       else
        if i <> ButtLen then
           WriteCharXY(x+i-1, y+j-1, ButtAttr , ' ')
         else
            WriteCharXY(x+i-1, y+j-1, ButtShadow, '-')
     end;
    end
    else
      if j = ButtW then
        begin
          for i :=1 to ButtLen do
            if i=1 then
              WriteCharXY(x+i-1, y+j-1, ButtShadow, ' ')
            else
          WriteCharXY(x+i-1, y+j-1, ButtShadow, '-');
        end
      else
        for i := 1 to ButtLen do
          if i<>ButtLen then
            WriteCharXY(x+i-1, y+j-1, ButtAttr , ' ')
          else
            WriteCharXY(x+i-1, y+j-1, ButtShadow , '-');
  end;
end;
{-------------------------}
Procedure SetButtSize(l, z : Byte);
begin
  ButtLen:=l;
  ButtW := z;
end;
{-------------------------}
Procedure SetWindChar(Ch : Char);
begin
  WindChar := Ch;
end;
{-------------------------}
Procedure ClrScr; Assembler;
asm
 mov  ax, 3
 int  $10
end;
{------------------}
Function ReadKey : Char; Assembler;
asm
   mov ah, 07h
   int 21h
end;
{----------------}
Procedure PutChr(C:Char; Col : Byte); Assembler;
asm
   mov ah, $09
   mov bh, 0
   mov bl, Byte Ptr Col
   mov al, Byte ptr C
   mov cx, 1
   int $10
end;
{----------------}
Procedure PutCursor(xx, yy : Byte);
begin
 xt := xx;
 yt := yy;
 asm
   mov ah, 2
   mov dh, Byte Ptr yy
   mov dl, Byte Ptr xx
   dec dh
   dec dl
   mov bh, 0
   int $10
 end;
end;
{------------------}
Procedure CursorOff;Assembler;
asm
 mov ah, 1
 mov ch, $20
 int $10
end;
{------------------}
Procedure CursorOn;Assembler;
asm
 mov ah, 1
 mov ch, 6
 mov cl, 7
 int $10
end;
{------------------}
Procedure WriteLine(S : String; Attr : Byte);
var
  i : Word;
begin
 with Window do
  for i := 1 to Byte(S[0]) do
   if (xt<=Xr) and (yt<=Yr) then
     begin
       if S[i]<>#32 then
         PutChr(S[i], Attr)
       else
         PutChr(WindChar , Attr);
       PutCursor(xt+1, yt);
     end;
end;
{------------------------}
Procedure SetAttr(Tx, BkTx : Byte; var Attr : Byte);
begin
  Attr := (Tx and $8F) or ((BkTx and 7) shl 4) or (BkTx and $80)
end;
{-----------------}
Procedure UnPackAttribute(Attr: Byte; var Text, Back: Byte);
begin
  Text := Attr and $8F;
  Back := (Attr shr 4) and 7
end;   {UnPackAttribute}
{------------------}
Procedure SaveTexBar(x1, y1, x2, y2 : Byte; P : Pointer);
var
 i, j : Byte;
 Xa, Ya : Byte;
 PT : PTar;
begin
  PT := P;
  Ya := Abs(y2-y1)+1;
  Xa := Abs(x2-x1)+1;
  for j := 1 to Ya do
    for i := 1 to Xa do
       PT^[(j-1)*Xa+i] := MemW[$B800:2*(80*(y1-2+j)+x1+i-2)];
end;
{----------------------}
Procedure RestoreTexBar(x1, y1, x2, y2 : Byte; P : Pointer);
var
 i, j : Byte;
 Xa, Ya : Byte;
 PT : PTar;
begin
  PT := P;
  Ya := Abs(y2-y1)+1;
  Xa := Abs(x2-x1)+1;
  for j := 1 to Ya do
    for i := 1 to Xa do
      MemW[$B800:2*(80*(y1-2+j)+x1+i-2)] := PT^[(j-1)*Xa+i];
end;
{-------------------}
Procedure SaveBar(xx1, yy1, xx2, yy2 : Byte);
var
  Size : Word;
begin
  inc(NSav);
  with TextSize[NSav] do
   begin
    x1 := xx1;
    y1 := yy1;
    x2 := xx2;
    y2 := yy2;
    Attrib := WinAttr;
    Size := (Abs(x2-x1)+1)*(Abs(y2-y1)+1);
   end;
  GetMem(TextSize[NSav].PMS, (Size+1)*2);
  if TextSize[NSav].PMS = NIL then else;
  with TextSize[NSav] do
    SaveTexBar(x1, y1, x2, y2, PMS);
end;
{--------------------}
Procedure DoMenuLine(x, y : Byte; KeyS, MenuS : String);
var
  Size : Word;
begin
  inc(NSav);
  with TextSize[NSav] do
   begin
    x1 := x;
    y1 := y;
    x2 := x + Length(KeyS)+Length(MenuS) ;
    y2 := y;
    Size := Abs(x2-x1)+1;
   end;
  GetMem(TextSize[NSav].PMS, (Size+1)*2);
  if TextSize[NSav].PMS = NIL then else;
  with TextSize[NSav] do
    SaveTexBar(x1, y1, x2, y2, PMS);
  PutCursor(x, y);
  WriteLine(KeyS, MnAttrK);
  WriteLine(Menus, MnAttrM);
end;
{----------------------}
Procedure WriteCharXY(x, y, Attr : Byte; c : Char);
begin
  PutCursor(X, Y);
  PutChr(c, Attr);
end;
{-------------------------}
Procedure Border (X1,Y1,X2,Y2,Bord: Byte);
  {Обводит рамкой заданную прямоугольную область экрана}
var
  i : Integer;
begin
  {Проверяем параметры обращения}
  if not ( (X1<1) or (X2<=X1) or
          (Y1<1) or (Y2<=Y1)  or (Bord>2)) then
    begin
      WriteCharXY(X1,Y1,WBorderAttr,BorderChar[Bord,1]);
      for i := 1 to X2-X1-1 do   		{Верхняя рамка}
        WriteCharXY(X1+i,Y1,WBorderAttr,BorderChar[Bord,2]);
      WriteCharXY(X2,Y1,WBorderAttr,BorderChar[Bord,3]);
      for i := 1 to Y2-Y1-1 do  		{Боковые стороны}
        begin
          WriteCharXY(X1,Y1+i,WBorderAttr,BorderChar[Bord,4]);
          WriteCharXY(X2,Y1+i,WBorderAttr,BorderChar[Bord,4])
        end;
      WriteCharXY(X1,Y2,WBorderAttr,BorderChar[Bord,5]);
      for i := 1 to x2-x1-1 do   		{Нижняя рамка}
        WriteCharXY(X1+i,Y2,WBorderAttr,BorderChar[Bord,2]);
      WriteCharXY(X2,Y2,WBorderAttr,BorderChar[Bord,6])
    end
end    {Border};
{-------------------------}
Procedure PutWindow(X1,Y1,X2,Y2,Bord: Byte;Header: String);
var
  x, y, SizeX, SizeY : Byte;
begin
 Border(X1,Y1,X2,Y2,Bord);
 SizeX := Abs(X2-X1)+1;
 SizeY := Abs(Y2-Y1)+1;
 for y := 1 to SizeY-2 do
   for x := 1 to SizeX-2 do
     WriteCharXY(X1+x,Y1+y, WinAttr, WindChar);
     if (Length(Header) > SizeX-2) and (SizeX>4) then
       begin
        Header[0]:=Char(SizeX-2);
        x:=Byte(Header[0]);
        Header[x-2] := '.';
        Header[x-1] := '.';
        Header[x]   := '.';
       end;
   If SizeX<=4 then Header[0]:=#0;
   SizeX := X1+(Abs(X2-X1)-Length(Header)) div 2;
   for x := 1 to Byte(Header[0]) do
    WriteCharXY(SizeX+x, Y1, WinHAttr, Header[x]);
    WindowSize(X1+1, Y1+1, X2-1, Y2-1);
end;
{---------------------------}
Procedure SetWindow (X1,Y1,X2,Y2,Bord: Byte;
       Header: String; Build: Boolean);
  {Создает окно в активной страницеи обводит его рамкой}
var
  xx1,yy1,xx2,yy2,x,y,dx,dy,k: Byte;
  dt: Integer;
const
  N     = 10;
begin
  if Build and ((x2-x1>=4) or (y2-y1>=4)) then
    begin
  {Начальное положение левого верхнего угла окна}
      x := (x2-x1) div 2;
      y := (y2-y1) div 2;
  {Количество промежуточных окон}
      dx := ((x2-x1) div 2) div N;
      dy := ((y2-y1) div 2) div N;
      if dx=0 then
        inc(dx);
      if dy=0 then
        inc(dy);
      if x>1 then
        begin
          xx1 := x1+x-1;
          xx2 := x2-x+1
        end
      else
        begin
          xx1 := x1;
          xx2 := x2
        end;
      if y>1 then
        begin
          yy1 := y1+y-1;
          yy2 := y2-y+1
        end
      else
        begin
          yy1 := y1;
          yy2 := y2
        end;
      for k := 0 to N-1 do   		{Цикл построения}
        begin
          PutWindow(xx1,yy1,xx2,yy2,Bord,Header);
          {Увеличиваем границы окна}
          if xx1>x1 then
            dec(xx1,dx);
          if xx2y1 then
            dec(yy1,dy);
          if yy20) or (PMin <>0) then
          Delay(PMax, PMin)
        end;
    end;
  PutWindow(X1,Y1,X2,Y2,Bord,Header)
end;   {SetWindow}
{-------------------}
Procedure UndoMenu;
var
  Size : Word;
begin
 if NSav>0 then
  begin
   with TextSize[NSav] do
    begin
     Size := Abs(x2-x1)+1;
     RestoreTexBar(x1, y1, x2, y2, PMS);
    end;
   FreeMem(TextSize[NSav].PMS, (Size+1)*2);
   dec(NSav);
   with TextSize[NSav] do
    begin
     WindowSize(Abs(x1+1), Abs(y1+1), Abs(x2-1),Abs(y2-1));
     WinAttr := Attrib;
    end;
  end;
end;
{-------------------}
Procedure RestoreScreen;
begin
 for i := 1 to NSav do
   UndoMenu;
 CursorOn;
 WindowSize(1, 1, 80, 25);
end;
{-------------------}
Procedure WindowSize(X1, Y1, X2, Y2 : Byte);
begin
  with Window do
   begin
    if X1 < X2 then
     begin
       X0 := X1;
       Xr := X2;
     end
    else
     begin
       X0 := X1;
       Xr := X2;
     end;
    if Y1 < Y2 then
     begin
       Y0 := Y1;
       Yr := Y2;
     end
    else
     begin
       Y0 := Y1;
       Yr := Y2;
     end;
   end;
end;
{---------------}
{Procedure WriteLn(S : String; z : Word);
begin
    WriteLine(S, WinAttr);
    Write(z);
    LFCR;
end;}
{--------------}
Procedure ZZCursor;
begin
 With Window do
  PutCursor(X0, Y0);
end;
{-----------------}
Procedure NewLine;
begin
 With Window do
  PutCursor(X0, Yt+1);
end;
{===========}
begin
  ResetTimer;
  NSav := 0;
  WindowSize(1, 1, 80, 25);
end.

Назад