{$IFNDEF OS2}
{$O+,F+}
{$ENDIF}
{$I-}

Unit aDir;

{*********************************************************}
{*                      ADIR.PAS                         *}
{*                                                       *}
{*  Copyright (c) Anton the Deinow, 1995,                *}
{*  Copyright (c) Konstantin Klyagin, 1995-98,           *}
{*                exspecially for Tornado BBS System     *}
{*                                                       *}
{*********************************************************}

Interface

Uses
{$IFNDEF WIN32}
  DOS,
  OpInLine,
  tWin,
{$ELSE}
  Classes,
  SysUtils,
{$ENDIF}
{$IFDEF OS2}
  VPSysLow,
  VPutils,
{$ENDIF}
  Objects,
  tMisc,
  OpCrt,
  TGlob;

Type
  tItemView = (ivAllInfo, ivOnlyName);

  tPaneColor = (
  pcWindow,
  pcFrame,
  pcHeader,
  pcItem,
  pcMarkedItem,
  pcCursor,
  pcCursorMarked,
  pcTitle,
  pcDivider,
  pcfInfo,
  pcmInfo
  );

  PaneColorArray = Array [tPaneColor] Of Byte;

  tPaneMode = (
  pmMultiFull,       {полное окно, внизу инф-я о тек.и отмеч-ых файлах}
  pmMultiHalf,       {окно на пол-экpана, остальное, как в пpедыдущем}
  pmSingleFull,      {полное, без отметки файлов}
  pmSingleHalf       {половина, без отметки файлов}
  );

  pnState = (
  pnOk,
  pnNotEnoughMem,
  pnNoFiles,
  pnInvalidPath,
  pnDriveNotReady,
  pnQuit
  );

  tPaneCmd = (
  ckLeftArrow,          {Left}
  ckRightArrow,         {Right}
  ckMarkItem,           {Ins}
  ckEnter,              {Enter}
  ckUpArrow,            {Up}
  ckDownArrow,          {Down}
  ckQuit,               {Esc}
  ckNone,               {Ctrl/Enter}
  ckHome,               {Home}
  ckEnd,                {End}
  ckPgUp,               {PgUp}
  ckPgDn,               {PgDn}
  ckGoTo,               {Any letter key}
  ckBackSpace,          {BackSpace}
  ckSelectAll,          {Gray +}
  ckDeSelectAll,        {Gray -}
  ckInverse,            {Gray *}
  ckChangeDrive         {Shift-A-B-C..Z}
  );

  FNameStr = String [90];

  DirRec = Record
    oFlag, dAttr : Byte;
    dTime, dSize : LongInt;
    dName        : FNameStr;
  End;

  DirRecPtr = ^DirRec;

  tPaneMetrix = Record
    Y2, TopY,
    BottomY,
    CurItemInfoY,
    MarkedInfoY : Byte;
  End;

  tPaneRec = Record
    ItemView : tItemView;
    PaneWin : PBoxRec;
    X1, Y1, X2 : Byte;
    PM : tPaneMetrix;
    AtTop, CurItem, TotalItems : Word;
    pnPath : PathStr;
    Colors : PaneColorArray;
    MarkedSize : LongInt;
    MarkedCount, NextMarked : Word;
      { -содеpжит номеp последнего помеченного файла,
        котоpый веpнула ф-я NextMarkedFile() }

    FoundMarked: Word;
      { -сколько уже возвpащено помеченых файлов }

    DirArray   : Pointer;
  End;

Const
  firstCk = ckLeftArrow;
  lastCk = ckEnd;
  hpfs : Boolean = False;

Var
  pnStatus : pnState;
  Pane : ^tPaneRec;
  Pivot : DirRec;     { используется пpи соpтиpовке                        }
  TmpDir : FNameStr;  { для установки куpсоpа на каталог из котоpого вышли }
  SaveDir : PathStr;
  DateMask : String [10];
  Opened : Boolean;
  CurPos, X, Y : Byte;
  {Charz: Array [1..12] Of Char;}
  Drive2Change : Char;

Function Pane_Process (xL, yL: Byte; pm_: tPaneMode; iv_: tItemView;
         Var pth: PathStr; DM: String; Blinking: Boolean;
         Var MarkedFilesColl: PNotSortedCollection): pnState;

{-основная пpоцедуpа pаботы с панелью}

Implementation

Const
  PaneMetrix: Array [tPaneMode] Of tPaneMetrix = (
  (Y2: 22; TopY: 2; BottomY: 18; CurItemInfoY: 20; MarkedInfoY: 21), {MultiFull}
  (Y2: 12; TopY: 2; BottomY: 8; CurItemInfoY: 10; MarkedInfoY: 11),  {MultiHalf}
  (Y2: 22; TopY: 2; BottomY: 19; CurItemInfoY: 21; MarkedInfoY: 0),  {SingleFull}
  (Y2: 12; TopY: 2; BottomY: 9; CurItemInfoY: 11; MarkedInfoY: 0)    {SingleHalf}
  );

  DefPaneColors1: PaneColorArray = (
  $87,  {pcWindow}
  $87,  {pcFrame}
  $30,  {pcHeader}
  $87,  {pcItem}
  $8E,  {pcMarkedItem}
  $30,  {pcCursor}
  $3E,  {pcCursorMarked}
  $8E,  {pcTitle}
  $87,  {pcDivider}
  $8F,  {pcfInfo}
  $8E   {pcmInfo}
  );

  DefPaneColors2: PaneColorArray = (
  $1b,  {pcWindow}
  $1b,  {pcFrame}
  $30,  {pcHeader}
  $1b,  {pcItem}
  $1E,  {pcMarkedItem}
  $30,  {pcCursor}
  $3E,  {pcCursorMarked}
  $1E,  {pcTitle}
  $1b,  {pcDivider}
  $1F,  {pcfInfo}
  $1E   {pcmInfo}
  );

  ofMarked = $01;  {файл помечен}
  MaxFiles = 500;

  HiddenChar: Array [Boolean] Of Char = (' ', '░');

  sUpDir : String [9] = #16'UP──DIR'#17;
  sSubDir: String [9] = #16'SUB─DIR'#17;

  OnlyNameDiv: Array [0..2] Of String [13] = (
  '            │',
  '            │',
  '            '
  );

  AllInfoDiv: String [38] = '            │         │        │      ';

  InfoDiv: Array [tItemView] Of String [38] = (
  '────────────┴─────────┴────────┴──────',
  '────────────┴────────────┴────────────'
  );

  ColumnTitle: Array [tItemView] Of String [38] = (
  '    Name    │   Size  │  Date  │ Time',
  '    Name         Name         Name'
  );

Function DirPtr (i: Word): DirRecPtr;
Type
  SO = Record
    O, S : Word;
  End;

Var
  P : Pointer;

Begin
  P := Pane^. DirArray;
  Inc (SO (P). O, SizeOf (DirRec) * (i-1));
  DirPtr := P;
End;

Function IntrnlToFname (dName: FNameStr): String;
Const
  HidPos : Array [Boolean] Of Byte = (9, 12);

Begin
  If dName [HidPos [hpfs]] = HiddenChar [True] Then dName [HidPos [hpfs]] := ' ';

  If hpfs Then IntrnlToFname := Copy (dName, 1, 12) Else
  If WordCount (dName, [' '] ) <> 1
  Then IntrnlToFname := ExtractWord (1, dName, [' ']) + '.' + ExtractWord (2, dName, [' '])
  Else IntrnlToFname := TrimTrail (dName);
End;

Function IntrnlFname (nme: String; Attr: Byte): String;
Begin
  If Attr And Directory = 0 Then Nme := LoString (Nme);

  If Nme <> '..' Then
  Begin
    If hpfs Then
    Begin
      If Length (Nme) > 12 Then
        IntrnlFname := Copy (Nme, 1, 10) + '..'
      Else
        IntrnlFname := Pad (Nme, 12);
    End Else
    Begin
      If Pos ('.', Nme) <> 0 Then
        IntrnlFname := Pad (Copy (Nme, 1, Pred (Pos ('.', Nme) ) ), 8) +
        HiddenChar [ (Attr And Hidden) <> 0] +
        Pad (Copy (Nme, Succ (Pos ('.', Nme) ), 3), 3)
      Else
        IntrnlFname := Pad (Nme, 8) + Pad (HiddenChar [ (Attr And Hidden) <> 0], 4)
    End;
  End Else
    IntrnlFname := Pad (Nme, 12);
End;

Function FindNextMarked: DirRecPtr;
Var
  i  : Word;
  dp : DirRecPtr;

Begin
  With Pane^ Do
  For i := NextMarked To TotalItems Do
  Begin
    dp := DirPtr (i);

    If dp^. oflag And ofMarked <> 0 Then
    Begin
      NextMarked := i;
      FindNextMarked := dp;
      Exit;
    End;
  End;

  FindNextMarked := Nil;
End;

Function GetCurrent: PathStr;
{-веpнет путь/имя текущего файла}
Begin
  With Pane^ Do
  If TotalItems <> 0 Then
  With DirPtr (CurItem)^ Do
  Begin
    If dAttr And Directory <> 0
    Then
      GetCurrent := AddBackSlash (pnPath) + IntrnlToFname (dName) + '\'
    Else
      GetCurrent := AddBackSlash (pnPath) + IntrnlToFname (dName);
  End Else
    GetCurrent := '';
End;

Function FindFiles: Boolean;
Var
  sr: {$IFNDEF WIN32} SearchRec
      {$ELSE} TSearchRec
      {$ENDIF};

Function Less (Var X, Y: DirRec): Boolean;
{-веpнет TRUE если X <Y }
Var
  Xdir, Ydir : Boolean;

Begin
  Xdir := (X. dAttr And Directory = Directory);
  Ydir := (Y. dAttr And Directory = Directory);
  If Xdir = Ydir Then Less := X. dName < Y. dName Else Less := Xdir;
End;

{$IFNDEF OS2}
{$S+}    {-отpубить контpоль пеpеполнения стека на момент соpтиpовки}
{$ENDIF}

Procedure Sort (L, R: Word);
{-соpтиpовка символов увеличением адpеса в пpомежутке [L..R] }
Var
  I, J: Word;

Begin
  I := L;
  J := R;
  Move (DirPtr ( (L + R) ShR 1)^, Pivot, SizeOf (DirRec) );

  Repeat
    While Less (DirPtr (I)^, Pivot) Do Inc (I);
    While Less (Pivot, DirPtr (J)^) Do Dec (J);
    If I <= J Then
    Begin
      { меняем местами элементы No I с No J }
      ExchangeStructs (DirPtr (I)^, DirPtr (J)^, SizeOf (DirRec) );
      Inc (I);
      Dec (J);
    End;
  Until I > J;

  If L < J Then Sort (L, J);
  If I < R Then Sort (I, R);
End;

{$IFNDEF OS2}
{$S-}
{$ENDIF}

Begin
  FindFiles := False;

  With Pane^ Do
  Begin
  {$IFDEF WIN32}
    DOSerror :=
  {$ENDIF}
    FindFirst (AddBackSlash (pnPath) + '*.*', AnyFile{$IFNDEF OS2}-VolumeID{$ENDIF} , sr);

    If DosError <> 0 Then
    Begin
      Case DosError Of
          3 : pnStatus := pnInvalidPath;
         18 : pnStatus := pnNoFiles;
        152 : pnStatus := pnDriveNotReady;
      End;

    {$IFNDEF MSDOS}
      FindClose (sr);
    {$ENDIF}
      Exit;
    End;

    While (DosError = 0) And (Pane^. TotalItems < MaxFiles) Do
    Begin
      If (((sr. Attr And VolumeID) = 0) And (sr. Name <> '.')) And (Not
         ((sr. Name = '..') And (Length (AddBackSlash (pnPath)) <= 3))) Then
      Begin
        Inc (TotalItems);
        With DirPtr (TotalItems)^ Do
        Begin
          dName := SR. Name;
          oFlag := 0;
          dAttr := SR. Attr;
          dTime := SR. Time;
          dSize := SR. Size;
        End;
      End;
    {$IFDEF WIN32}
      DOSerror :=
    {$ENDIF}
      FindNext (sr);
    End;

  {$IFNDEF MSDOS}
    FindClose (sr);
  {$ENDIF}

    If TotalItems <> 0 Then
    Begin
      CurItem := 1;
      AtTop := 1;

      If TotalItems > 1 Then
      If Pos ('..', DirPtr (1)^. dName) = 0
      Then
        Sort (1, TotalItems)
      Else
        If TotalItems > 2 Then Sort (2, TotalItems);
    End;
  End;

  FindFiles := True;
End;

Procedure Pane_Done;
{-завеpшает панель}
Begin
  If Pane = Nil Then Exit;
  CloseWindow (Pane^. PaneWin);
  Opened := False;
  If Pane^. DirArray <> Nil Then FreeMem (Pane^. DirArray, SizeOf (DirRec) * MaxFiles);
  FreeMem (Pane, SizeOf (tPaneRec));
End;

Procedure ShowColumnTitle;
Begin
  With Pane^ Do
  Begin
    FastWrite (ColumnTitle [ItemView], Y1 + 1, X1 + 1, Colors [pcTitle] );
    FastWrite ('│', Y1+1, 33, Colors [pcWindow]);
    FastWrite ('│', Y1+1, 46, Colors [pcWindow]);
  End;
End;

Procedure DrawDivider;
Begin
  With Pane^ Do
    FastWrite (InfoDiv [ItemView], PM. BottomY + 1, X1 + 1, Colors [pcDivider]);
End;

Procedure ShowCurInfo;
Var
  dt : DateTime;
  St : String;

Begin
  With DirPtr (Pane^. CurItem)^ Do
  Begin
    St := Pad (IntrnlToFname (dName), 13);

    If dAttr And Directory <> 0 Then
    If Pos ('..', St) <> 0 Then St := St + sUpDir Else St := St + sSubDir
    Else St := St + LeftPad (Long2Str (dSize), 9);

    UnpackTime (dTime, dt);
    St := St + ' ' + ReFormatDate (
    LeftPadCh (Long2Str (DT. Month), '0', 2) + '-' +
    LeftPadCh (Long2Str (DT. Day), '0', 2) + '-' +
    LeftPadCh (Long2Str (DT. Year), '0', 4), 'MM-DD-YYYY', DateMask)  + ' ' +
    LeftPadCh (Long2Str (dt. Hour), '0', 2) + ':' +
    LeftPadCh (Long2Str (dt. Min), '0', 2);
  End;

  With Pane^ Do FastWrite (St, PM. CurItemInfoY, X1 + 1, Colors [pcfInfo]);
End;

Procedure ShowMarkedInfo;
Begin
  With Pane^ Do
  Begin
    If PM. MarkedInfoY = 0 Then Exit;
    FastWrite (Pad ('', X2 - X1 - 1), PM. MarkedInfoY, X1 + 1, Colors [pcmInfo]);

    If MarkedCount = 0
    Then
      FastWrite (CenterCh ('No files selected', ' ', X2-X1-1), PM. MarkedInfoY, X1 + 1, Colors [pcmInfo])
    Else
      FastWrite (CenterCh (Long2Str (MarkedSize) + ' bytes in ' +
      Long2Str (MarkedCount) + ' marked files', ' ', X2-X1-1),
      PM. MarkedInfoY, X1 + 1, Colors [pcmInfo]);
  End;
End;

Function Pane_Open: Boolean;
{-откpывает/пеpеоткpывает панель}

Function ZoomedPath: String;
Var
  St  : String;

Begin
  With Pane^ Do
  If Length (pnPath) > 34 Then
    St := ' ' + Copy (pnPath, 1, 3) + '...' + Copy (pnPath,
    Length (pnPath) - 27, 28) + ' '
  Else
    St := ' ' + pnPath + ' ';

  If Not hpfs Then St := UpString (St);
  ZoomedPath := St;
End;

Procedure MarkerToDir;
Var
  w  : Word;
  St : String;

Begin
  With Pane^ Do
  If TmpDir <> '' Then
  For w := 1 To TotalItems Do
  Begin
    St := Trim (PlaceSubStr (DirPtr (w)^. dName, '░', ''));
    St := Trim (TmpDir);

    If Trim (PlaceSubStr (DirPtr (w)^. dName, '░', '')) = Trim (TmpDir) Then
    Begin
      CurItem := w;
      If w > Succ (PM. BottomY - PM. TopY) Then AtTop := w - (PM. bottomY - PM. TopY);
      Exit;
    End;
  End;
End;

Begin
  Pane_Open := False;
  hpfs :=
  {$IFDEF OS2} GetDriveType (Pane^. pnPath [1]) = dtHDHPFS
  {$ELSE} False {$ENDIF};

  With Pane^ Do
  Begin
    If Not Opened Then
    Begin
      InitWindow (PaneWin, X1, Y1, X2, PM. Y2, 4, Colors [pcWindow], '', $00, ZoomSpeed, False);
      DrawWindow (PaneWin);

      FastWrite (CenterCh (Replicate (' ', Length (ZoomedPath) - 1), '═',
      X2 - X1 - 1), Y1, X1 + 1, Colors [pcWindow]);

      FastWrite ('╤', Y1, 33, Colors [pcWindow]);
      FastWrite ('╤', Y1, 46, Colors [pcWindow]);
      FastWrite (ZoomedPath, Y1, X1 + 1 + (((X2-X1) - Length (ZoomedPath)) Div 2), Colors [pcHeader]);
      Opened := True;
    End Else
    Begin
      FastWrite ('╒' + CenterCh (Replicate (' ', Length (ZoomedPath) - 1), '═',
      X2 - X1 - 1) + '╕', Y1, X1, Colors [pcWindow]);

      FastWrite ('╤', Y1, 33, Colors [pcWindow]);
      FastWrite ('╤', Y1, 46, Colors [pcWindow]);
      FastWrite (ZoomedPath, Y1, X1 + 1 + (((X2 - X1) - Length (ZoomedPath)) Div 2), Colors [pcHeader]);
    End;

    MarkedSize := 0;
    MarkedCount := 0;
    ShowColumnTitle;
    TotalItems := 0;
    AtTop := 1;
    If Not FindFiles Then Exit;
    MarkerToDir;
  End;

  TmpDir := '';
  DrawDivider;
  ShowCurInfo;
  ShowMarkedInfo;

  Pane_Open := True;
End;

Function Pane_Process (xL, yL: Byte; pm_: tPaneMode; iv_: tItemView;
         Var pth: PathStr; DM: String; Blinking: Boolean;
         Var MarkedFilesColl: PNotSortedCollection): pnState;

Var
  St: String;

Procedure CalcXY (w: Word; Var X, Y: Byte);
Begin
  With Pane^ Do
  Begin
    X := Succ (X1) + 13 * ((w - AtTop) Div Succ (PM. BottomY - PM. TopY));
    Y := PM. TopY + ((w - AtTop) Mod Succ (PM. BottomY - PM. TopY));
  End;
End;

Function GetPaneCmd: tPaneCmd;
Var
  i: tPaneCmd;
  ck: Char;

Begin
  Repeat
    ck := ReadKey;
    i := ckNone;
    Case ck Of
       #0 : Begin
              Case ReadKey Of
                #75: i := ckLeftArrow;
                #77: i := ckRightArrow;
                #82: i := ckMarkItem;
                #72: i := ckUpArrow;
                #80: i := ckDownArrow;
                #71: i := ckHome;
                #79: i := ckEnd;
                #73: i := ckPgUp;
                #81: i := ckPgDn;
              End;
              CurPos := 0;
              HiddenCursor;
            End;

      #13 : i := ckEnter;
      #27 : i := ckQuit;
      #43 : i := ckSelectAll;
      #45 : i := ckDeSelectAll;
      #42 : i := ckInverse;

 'A'..'Z' : Begin
              i := ckChangeDrive;
              Drive2Change := ck;
            End;

    (*

#33..#122 : Begin
              i := ckGoTo;
              If CurPos <= 11 Then inc (CurPos);
              Charz [CurPos] := ck;
            End;

       #8 : Begin
              If (CurPos > 1) and (CurPos < 11) Then Dec (CurPos);
              If CurPos = 10 Then CurPos := 8;
              CalcXY (Pane^. CurItem, X, Y);
              GoToXY (X + CurPos - 1, Y);
            End;

    *)
    End;

    If i <> ckNone Then
    Begin
      GetPaneCmd := i;
      Exit;
    End;

  Until False;
End;

Procedure SetMarker;
Var
  X, Y, Clr : Byte;

Begin
  With Pane^ Do
  If TotalItems <> 0 Then
  Begin
    If DirPtr (Pane^. CurItem)^. oFlag And ofMarked = 0 Then
      Clr := Colors [pcCursor] Else Clr := Colors [pcCursorMarked];

    Case ItemView Of
      ivAllInfo : Begin
                    ChangeAttribute (Pred (X2 - X1), PM. TopY + (CurItem - AtTop), X1 + 1, Clr);
                    ShowCurInfo;
                  End;

     ivOnlyName : Begin
                    CalcXY (CurItem, X, Y);
                    ChangeAttribute (12, Y, X, Clr);
                    ShowCurInfo;
                  End;
    End;
  End;
End;

Procedure ClrMarker;
Var
  X, Y, c : Byte;

Begin
  With Pane^ Do
  Begin
    If DirPtr (CurItem)^. oFlag And ofMarked <> 0 Then
      c := Colors [pcMarkedItem]
    Else
      c := Colors [pcItem];

    Case ItemView Of
      ivAllInfo : ChangeAttribute (Pred (X2 - X1), PM. TopY + (CurItem - AtTop), X1 + 1, c);
     ivOnlyName : Begin
                    CalcXY (CurItem, X, Y);
                    ChangeAttribute (12, Y, X, c);
                  End;
    End;
  End;
End;

Procedure ShowFile (w: Word);
Var
  X, Y, c : Byte;
  dt      : DateTime;

Begin
  With Pane^ Do
  Begin
    c := Colors [pcItem];

    Case ItemView Of
      ivAllInfo:
                 Begin
                   If w > TotalItems Then St := AllInfoDiv
                   Else With DirPtr (w)^ Do
                   Begin
                     St := dName + '│';
                     If dAttr And Directory <> 0 Then
                     If dName [1] = '.'
                     Then St := St + sUpDir Else St := St + sSubDir
                     Else St := St + LeftPad (Long2Str (dSize), 9);
                     UnpackTime (dTime, dt);

                     St := St + '│' + ReFormatDate (LeftPadCh (Long2Str
                     (DT. Month), '0', 2) + '-' + LeftPadCh (Long2Str
                     (DT. Day), '0', 2) + '-' + LeftPadCh (Long2Str
                     (DT. Year), '0', 4), 'MM-DD-YYYY',
                     DateMask) + '│' + LeftPadCh (Long2Str (dt. Hour), '0', 2) +
                     ':' + LeftPadCh (Long2Str (dt. Min), '0', 2);

                     If oFlag And ofMarked <> 0 Then c := Colors [pcMarkedItem];
                   End;
                   FastWrite (St, w - AtTop + PM. TopY, X1 + 1, c)
                 End;

      ivOnlyName:
                  Begin
                    CalcXY (w, X, Y);
                    FastWrite (OnlyNameDiv [ (w - AtTop) Div Succ (PM. BottomY - PM. TopY) ], Y, X, Colors [pcItem] );
                    If w <= TotalItems Then
                    With DirPtr (w)^ Do
                    Begin
                      If (oFlag And ofMarked) <> 0 Then c := Colors [pcMarkedItem];
                      FastWrite (IntrnlFname (dName, dAttr), Y, X, c);
                    End;
                  End;
    End;
  End;
End;

Procedure ShowFiles;
Var
  w: Word;

Begin
  With Pane^ Do
  Case ItemView Of
    ivAllInfo  : For w := AtTop To AtTop + (PM. BottomY - PM. TopY) Do ShowFile (w);
    ivOnlyName : For w := AtTop To Pred (AtTop) + (PM. BottomY - PM. TopY + 1) * 3 Do ShowFile (w);
  End;
End;

Procedure MoveCursorDown;
Begin
  With Pane^ Do
  If CurItem < TotalItems Then
  Begin
    ClrMarker;
    Inc (CurItem);

    Case ItemView Of
      ivAllInfo : If CurItem > (AtTop + (PM. BottomY - PM. TopY) ) Then
                  Begin
                    Inc (AtTop);
                    ScrollWindowUp (X1 + 1, Y1 + 2, X2 - 1, PM. BottomY, 1);
                    ShowFile (CurItem);
                  End;

     ivOnlyName : If CurItem > (2 + AtTop + (PM. BottomY - PM. TopY) * 3) Then
                  Begin
                    Inc (AtTop);
                    ShowFiles;
                  End;
    End;
  End;
End;

Procedure MoveCursorUp;
Begin
  With Pane^ Do
  If CurItem > 1 Then
  Begin
    ClrMarker;
    Dec (CurItem);

    Case ItemView Of
      ivAllInfo : If CurItem < AtTop Then
                  Begin
                    Dec (AtTop);
                    ScrollWindowDown (X1 + 2, Y1 + 1, X2 - 1, PM. BottomY, 1);
                    ShowFile (CurItem);
                  End;

     ivOnlyName : If CurItem < AtTop Then
                  Begin
                    Dec (AtTop);
                    ShowFiles;
                  End;
    End;
  End;
End;

Procedure MoveCursorRight;

Var
  X, Y: Byte;
  z, w: Word;

Begin
  With Pane^, PM Do
    If (ItemView = ivOnlyName) And (CurItem < TotalItems) Then Begin
      z := AtTop;
      ClrMarker;
      If (CurItem + (BottomY - TopY) ) < TotalItems Then Begin
        w := CurItem;
        Inc (CurItem, Succ (BottomY - TopY) );
        If ( (w - AtTop) Div Succ (BottomY - TopY) ) = 2 Then
          If AtTop + (BottomY - TopY + 1) * 4 <= TotalItems Then
            Inc (AtTop, Succ (BottomY - TopY) )
          Else Begin
            CalcXY (w, X, Y);
            AtTop := Pred (TotalItems) - Succ ( (BottomY - TopY) * 3);
            CurItem := TotalItems - (BottomY - TopY) + (Y - TopY);
          End;
      End
      Else Begin
        CurItem := TotalItems;
        If TotalItems < (BottomY - TopY + 1) * 3 Then
          AtTop := 1
        Else
          AtTop := Pred (TotalItems) - Succ ( (BottomY - TopY) * 3);
      End;

      If AtTop <> z Then ShowFiles;
    End;
End;

Procedure MoveCursorLeft;
Var z, w: Word;

Begin
  With Pane^, PM Do
    If (ItemView = ivOnlyName) And (CurItem > 1) Then Begin
      z := AtTop;
      ClrMarker;
      If CurItem > Succ (BottomY - TopY) Then Begin
        w := CurItem;
        Dec (CurItem, Succ (BottomY - TopY) );
        If ( (w - AtTop) Div Succ (BottomY - TopY) ) = 0 Then
          If AtTop > Succ (BottomY - TopY)  Then
            Dec (AtTop, Succ (BottomY - TopY) )
          Else
            AtTop := 1;
      End
      Else Begin
        CurItem := 1;
        AtTop := 1;
      End;

      If AtTop <> z Then ShowFiles;
    End;
End;

Var
  Done         : Boolean;
  CurDir, sDir : PathStr;
  i            : Word;

Label
  EoP;

Begin  (*** Pane_Process ***)
  DateMask := DM;
  MarkedFilesColl^. DeleteAll;
  TmpDir := '';
  GetMem (Pane, SizeOf (tPaneRec) );
  If Pane = Nil Then
  Begin
    Pane_Process := pnNotEnoughMem;
    Exit;
  End;

  FillChar (Pane^, SizeOf (tPaneRec), 0);
  GetMem (Pane^. DirArray, SizeOf (DirRec) * MaxFiles);
  If Pane^. DirArray = Nil Then
  Begin
    Pane_Process := pnNotEnoughMem;
    FreeMem (Pane, SizeOf (tPaneRec) );
    Exit;
  End;

  GetDir (0, SaveDir);  {save original directory}

  (* If Length (pth) = 0 Then
    pth := SaveDir
  Else Begin *)

    pth := UpString (pth);
    If (Length (pth) = 2) And (pth [2] = ':') Then pth := pth + '\';

    St := JustFileName (pth);

    If (Pos ('*', St) <> 0) Or (Pos ('?', St) <> 0) Then
      pth := Copy (pth, 1, Pred (Pos (St, pth) ) );

  {End;}

  With Pane^, PaneMetrix [pm_] Do Begin
    ItemView := iv_;
    X1 := xL;
    Y1 := yL;
    X2 := xL + 39;
    pnPath := pth;
    If Blinking Then Colors := DefPaneColors2 Else Colors := DefPaneColors1;
    { дополнительные }
    PM. Y2 := Y1 + Y2;
    PM. TopY := Y1 + TopY;
    PM. BottomY := Y1 + BottomY;
    PM. CurItemInfoY := Y1 + CurItemInfoY;
    If MarkedInfoY <> 0 Then
      PM. MarkedInfoY := Y1 + MarkedInfoY;
  End;

  Opened := False;

  If Not Pane_Open Then
  Begin
    Pane_Process := pnStatus;
    Pane_Done;
    Exit;
  End;

  GetDir (0, CurDir);
  If CurDir <> pth Then ChDir (pth);

  GetDir (0, Pane^. pnPath);
  Pane_Open;
  ShowFiles;
  done := False;

  {=Основной цикл pаботы панели=}
  Repeat
    SetMarker;
    With Pane^ Do
      Case GetPaneCmd Of
        ckUpArrow: MoveCursorUp;
        ckDownArrow: MoveCursorDown;
        ckLeftArrow: MoveCursorLeft;
        ckRightArrow: MoveCursorRight;

        ckQuit:
                Begin
                  done := True;
                  Pane_Process := pnQuit;
                  pth := pnPath;
                End;

        ckEnter: With DirPtr (CurItem)^ Do
                 Begin
                   GetDir (0, TmpDir);
                   If dAttr and Directory <> 0 Then
                   Begin
                      St := dName;
                      If St = '..' Then
                      If Length (TmpDir) <= 3 Then GoTo EoP
                      Else TmpDir := Copy (TmpDir, rPos ('\', TmpDir, Length (TmpDir))+1, 255)
                      Else TmpDir := '';
                      ChDir (St);
                      DOSerror := IOResult;
                      GetDir (0, pnPath);
                      Pane_Open;
                      ShowFiles;
                   End Else
                   Begin
                     If MarkedCount = 0 Then
                     Begin
                       DirPtr (CurItem)^. oFlag := oFlag xor ofMarked;
                       Inc (MarkedSize, DirPtr (CurItem)^. dSize);
                       Inc (MarkedCount);

                       If Pos ('.', DirPtr (CurItem)^. dName) = 0 Then
                         DirPtr (CurItem)^. dName :=
                         DirPtr (CurItem)^. dName + '.';

                       MarkedFilesColl^. Insert (NewStr (AddBackSlash (
                       Pane^. pnPath) + DirPtr (CurItem)^. dName));

                     End Else
                        For i := 1 To TotalItems Do
                        If DirPtr (i) <> nil Then
                        If DirPtr (i)^. oFlag and ofMarked <> 0 Then
                        Begin
                          If Pos ('.', DirPtr (i)^. dName) = 0 Then
                            DirPtr (i)^. dName :=
                            DirPtr (i)^. dName + '.';

                          MarkedFilesColl^. Insert (NewStr (AddBackSlash (
                          Pane^. pnPath) + DirPtr (i)^. dName));
                        End;

                     done := True;
                     Pane_Process := pnOk;
                     pth := pnPath;
                   End;

                   EoP:
                 End;

        ckHome: If CurItem > 1 Then
                Begin
                  CurItem := 1;
                  AtTop := 1;
                  ShowFiles;
                End;

        ckEnd: If CurItem < TotalItems Then
               Begin
                 CurItem := TotalItems;
                 Case ItemView Of
                   ivAllInfo: If TotalItems > (PM. bottomY - PM. TopY) Then
                               AtTop := TotalItems - (PM. bottomY - PM. TopY);
                   ivOnlyName: If TotalItems < (PM. BottomY - PM. TopY + 1) * 3
                               Then AtTop := 1
                               Else AtTop := Pred (TotalItems) - Succ
                                             ((PM. BottomY - PM. TopY) * 3);
                 End;
                 ShowFiles;
               End;

        ckMarkItem: If PM. MarkedInfoY <> 0 Then
                      With DirPtr (CurItem)^ Do
                        If dAttr And Directory = 0 Then
                        Begin
                          oFlag := oFlag XOr ofMarked;
                          If oFlag And ofMarked <> 0 Then
                          Begin
                            Inc (MarkedSize, dSize);
                            Inc (MarkedCount);
                          End Else
                          Begin
                            Dec (MarkedSize, dSize);
                            Dec (MarkedCount);
                          End;

                          ShowMarkedInfo;
                          MoveCursorDown;
                        End;

         ckInverse: If PM. MarkedInfoY <> 0 Then
                    Begin
                      For i := 1 To TotalItems Do
                      Begin
                        With DirPtr (i)^ Do
                          If dAttr And Directory = 0 Then
                          Begin
                            oFlag := oFlag XOr ofMarked;
                            If oFlag And ofMarked <> 0 Then
                            Begin
                              Inc (MarkedSize, dSize);
                              Inc (MarkedCount);
                            End Else
                            Begin
                              Dec (MarkedSize, dSize);
                              Dec (MarkedCount);
                            End;
                            ShowMarkedInfo;
                          End;
                      End;
                      ShowFiles;
                    End;

        ckSelectAll: If PM. MarkedInfoY <> 0 Then
                     Begin
                       For i := 1 To TotalItems Do
                       Begin
                         With DirPtr (i)^ Do
                         If dAttr And Directory = 0 Then
                         Begin
                           If oFlag And ofMarked = 0 Then
                           Begin
                             oFlag := oFlag XOr ofMarked;
                             Inc (MarkedSize, dSize);
                             Inc (MarkedCount);
                           End;
                         End;
                         ShowMarkedInfo;
                       End;
                       ShowFiles;
                     End;

        ckDeSelectAll: If PM. MarkedInfoY <> 0 Then
                       Begin
                         For i := 1 To TotalItems Do
                         Begin
                           With DirPtr (i)^ Do
                           If dAttr And Directory = 0 Then
                           Begin
                             If oFlag And ofMarked <> 0 Then
                             Begin
                               oFlag := oFlag XOr ofMarked;
                               Dec (MarkedSize, dSize);
                               Dec (MarkedCount);
                             End;
                           End;
                           ShowMarkedInfo;
                         End;
                         ShowFiles;
                       End;
        (*
        ckGoTo: Begin
                  For i := CurItem To TotalItems Do
                  Begin
                    NotFound := False;

                    If Charz [CurPos] = '.' Then
                    Begin
                      CurPos := 9;
                      Charz [1] := ' ';
                      Charz [2] := ' ';
                      Charz [3] := ' ';
                      Charz [4] := ' ';
                      Charz [5] := ' ';
                      Charz [6] := ' ';
                      Charz [7] := ' ';
                      Charz [8] := ' ';
                      Charz [9] := '.';
                      CalcXY (AtTop, X, Y);
                      GoToXY (X + CurPos, Y);
                      NormalCursor;
                      Break;
                    End;

                    If CurPos < 9 Then
                    For j := 1 To CurPos Do
                    Begin
                      If DirPtr (i)^. dName [j] <> Charz [j]
                         Then NotFound := True;
                    End Else

                    For j := 10 To CurPos Do
                    If DirPtr (i)^. dName [j] <> Charz [j] Then
                       NotFound := True;

                    If Not NotFound Then
                    Begin
                      CurItem := i;
                      AtTop := i;
                      CalcXY (AtTop, X, Y);
                      GoToXY (X + CurPos - 1, Y);
                      NormalCursor;
                      Break;
                    End;

                  End;
                  ShowFiles;
                End;
        *)

        ckChangeDrive : Begin
                          GetDir (0, sDir);
                          ChDir (Drive2Change + ':\');

                          If IOResult <> 0 Then
                            ChDir (sDir) Else
                          Begin
                            GetDir (0, pnPath);
                            Pane_Open;
                            ShowFiles;
                          End;
                        End;

        ckPgUp: Begin
                  If TotalItems - TotalItems + CurItem - 1 > 21
                     Then Dec (CurItem, 21)
                     Else CurItem := 1;

                  AtTop := CurItem;
                  ShowFiles;
                End;

        ckPgDn: Begin
                  If TotalItems - CurItem > 21
                     Then Inc (CurItem, 21)
                     Else CurItem := TotalItems;

                  AtTop := CurItem;
                  ShowFiles;
                End;

      End;
  Until done;
  ChDir (SaveDir);
  Pane_Done;
End;

End.
