unit frmAltMenuUnt;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, ComCtrls, Grids, HandTIA, Profile, StdCtrls, Buttons;

type
  TMyThread = Class(TThread)
  Private
    { Private declarations }

    Item  : TFileListItem;
    I     : Integer;
    St    : String;
    SS    : String;
    BF    : String;
    BB    : String;
    BS    : String;
    CS    : String;
    MP    : String;
    Procedure LoadInfo(I: Integer);
    Procedure Sync;
  Protected
    Procedure Execute; Override;
  Public
    Constructor Create;
  End;

  TMyStringGrid = Class(TStringGrid)
  Public
    Procedure DrawCell(ACol,ARow: LongInt; ARect: TRect;
                       AState: TGridDrawState); Override;
  End;

  TfrmAltMenu = class(TForm)
    Panel1: TPanel;
    sbMain: TStatusBar;
    Panel2: TPanel;
    imgScreenShot: TImage;
    imgBoxFrontScan: TImage;
    imgCartScan: TImage;
    imgBoxBackScan: TImage;
    Panel3: TPanel;
    imgBoxSideScan: TImage;
    btnManual: TBitBtn;
    procedure FormShow(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormResize(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Splitter1Moved(Sender: TObject);
    procedure btnManualClick(Sender: TObject);
  private
    { Private declarations }
    FileList : TList;
    Click    : Boolean;
    MyThread : TMyThread;
    Procedure LoadStringGrid;
    Procedure LoadImages(FileName: String);
    Procedure ClearImage(Var Img: TImage; Stretch: Boolean);
    Procedure GetProfileSettings;
    Procedure ProcessChosenCart(Ch: Char; Item: TFileListItem);
    procedure sgMainDrawCell(Sender: TObject; ACol, ARow: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure sgMainDblClick(Sender: TObject);
    procedure sgMainKeyPress(Sender: TObject; var Key: Char);
    procedure sgMainMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
//    procedure sgMainSelectCell(Sender: TObject; ACol,
//      ARow: Integer; var CanSelect: Boolean);
  public
    sgMain   : TMyStringGrid;
    Sort     : TMenuSort;
    SortAsc  : Boolean;
    Procedure LoadSelImages;
    Procedure SortFileList(FileList: TList; P,R: Integer);
    Procedure OpenFile(Const FileName: String; Img: TImage; ZIP: Boolean);
  end;

var
  frmAltMenu: TfrmAltMenu;

implementation

{$R *.DFM}

Uses frmInfoUnt, AtariControls, frmMenuunt, JPEG, frmProfileSettingsUnt,
  frmManualUnt, ZipMstr, frmMainunt;

Const
  CartName : Array[TCart] Of String =
   ('Standard','Standard','8k','16k','Super-chip','Parker Bros.',
    'M-Network','Supercharger','CBS RAM-Plus','TigerVision','Pitfall II',
    'Activision 8k','Mega Boy','32-in-1','CommaVid','Compumate','');
  ContName : Array[TController] Of String =
   ('Joystick','Paddle','Video Touch Pad','Indy 500 Driving','Keyboard',
    'CBS Booster-Grip','');

Var
  OldController : TController;
  LastClick     : Integer;
  ThreadDone    : Boolean;

Procedure TMyStringGrid.DrawCell(ACol,ARow: LongInt; ARect: TRect;
                   AState: TGridDrawState);
Begin
  Inherited DrawCell(ACol,ARow,ARect,AState);
End; // TMyStringGrid.DrawCell

Procedure TMyThread.LoadInfo(I: Integer);
Var ZIP: Boolean;
Begin
  Case I Of
    1: Begin
         Item.ScreenShot   := FileExistsZip(SS + St + '.JPG',False,ZIP) Or
                              FileExistsZip(SS + St + '.BMP',False,ZIP);
         Item.Extras := '';
       End;
    2: Begin
         Item.BoxFrontScan := FileExistsZip(BF + St + '.JPG',False,ZIP) Or
                              FileExistsZip(BF + St + '.BMP',False,ZIP);
         If Item.BoxFrontScan Then Item.Extras := Item.Extras + 'F';
       End;
    3: Begin
         Item.BoxBackScan  := FileExistsZip(BB + St + '.JPG',False,ZIP) Or
                              FileExistsZip(BB + St + '.BMP',False,ZIP);
         If Item.BoxBackScan Then Item.Extras := Item.Extras + 'B';
       End;
    4: Begin
         Item.BoxSideScan  := FileExistsZip(BS + St + '.JPG',False,ZIP) Or
                              FileExistsZip(BS + St + '.BMP',False,ZIP);
         If Item.BoxSideScan Then Item.Extras := Item.Extras + 'S';
       End;
    5: Begin
         Item.CartScan     := FileExistsZip(CS + St + '.JPG',False,ZIP) Or
                              FileExistsZip(CS + St + '.BMP',False,ZIP);
         If Item.CartScan Then Item.Extras := Item.Extras + 'C';
       End;
    6: Begin
         Item.Manual       := FileExistsZip(MP + St + '.RTF',False,ZIP)  Or
                              FileExistsZip(MP + St + '.TXT',False,ZIP)  Or
                              FileExistsZip(MP + St + '.HTM',False,ZIP)  Or
                              FileExistsZip(MP + St + '.HTML',False,ZIP) Or
                              FileExistsZip(MP + St + '.PDF',False,ZIP);
         If Item.Manual Then Item.Extras := Item.Extras + 'M';
       End;
  End; // Case
  Synchronize(Sync);
End; // TMyThread.LoadInfo

Procedure TMyThread.Sync;
Var
  J     : Integer;
  State : TGridDrawState;
  R     : TRect;

Begin
  State := [];
  If I = frmAltMenu.sgMain.Row - 1 Then State := State + [gdSelected];
  R := frmAltMenu.sgMain.CellRect(0,I + 1);
  If R.Top > 0 Then
   For J := 0 To 8 Do frmAltMenu.sgMain.DrawCell(J,I + 1,frmAltMenu.sgMain.CellRect(J,I + 1),State);
End; // TMyThread.Sync

Constructor TMyThread.Create;
Begin
  FreeOnTerminate := True;
  Inherited Create(False);
End; // TMyThread.Create

Procedure TMyThread.Execute;
Var
  NameList : TStringList;

  Procedure Load(J: Integer);
  Begin
    I := 0;
    While I < NameList.Count Do
    Begin
      Item := TFileListItem(frmAltMenu.FileList[I]);
      St   := NameList.Strings[I];
      LoadInfo(J);
  //    Synchronize(LoadInfo);
      If Terminated Then
      Begin
        ThreadDone := True;
        Exit;
      End;
      Inc(I);
    End; // While
  End; // Load

Begin
  { Place thread code here }

  NameList := TStringList.Create;
  I := 0;
  While I < frmAltMenu.FileList.Count Do
  Begin
    Item := TFileListItem(frmAltMenu.FileList[I]);
    St   := RemoveFileExt(ExtractFileName(Item.Name));
    NameList.Add(St);
    Inc(I);
  End; // While

  SS := Config.ScreenShotPath;
  BF := Config.BoxFrontScanPath;
  BB := Config.BoxBackScanPath;
  BS := Config.BoxSideScanPath;
  CS := Config.CartScanPath;
  MP := Config.ManualPath;
  If (SS <> '') And Not (SS[Length(SS)] In [':','\']) Then SS := SS + '\';
  If (BF <> '') And Not (BF[Length(BF)] In [':','\']) Then BF := BF + '\';
  If (BB <> '') And Not (BB[Length(BB)] In [':','\']) Then BB := BB + '\';
  If (BS <> '') And Not (BS[Length(BS)] In [':','\']) Then BS := BS + '\';
  If (CS <> '') And Not (CS[Length(CS)] In [':','\']) Then CS := CS + '\';
  If (MP <> '') And Not (MP[Length(MP)] In [':','\']) Then MP := MP + '\';
  Load(1);
  Load(2);
  Load(3);
  Load(4);
  Load(5);
  Load(6);
  NameList.Free;
  frmAltMenu.sgMain.Invalidate;
  ThreadDone := True;
End; // TMyThread.Execute

Procedure TfrmAltMenu.SortFileList(FileList: TList; P,R: Integer);
Var Q: Integer;

  Function Partition(P,R: Integer): Integer;
  Var
    Item  : TFileListItem;
    Item1 : TFileListItem;
    Item2 : TFileListItem;
    I,J   : Integer;

    Function Equal(Item,Item1: TFileListItem): Integer;
    Var
      B : Integer;
      S : TMenuSort;

      Function TestEqual(S: TMenuSort): Integer;
      Var
        B     : Integer;
        St1   : String;
        St2   : String;
        Y1,Y2 : Integer;

      Begin
        B := 0;
        Case S Of
          msName:
          Begin
            St1 := UpperCase(Item.RNam);
            St2 := UpperCase(Item1.RNam);
            B   := CompareStr(St2,St1);
          End;
          msSize:
          Begin
            If Item1.Size = Item.Size Then B := 0 Else
             If Item1.Size < Item.Size Then B := -1 Else B := 1;
          End;
          msType:
          Begin
            If Item.Prof <> Nil
             Then St1 := UpperCase(CartName[Item.Prof.Cart])
             Else St1 := '';
            If Item1.Prof <> Nil
             Then St2 := UpperCase(CartName[Item1.Prof.Cart])
             Else St2 := '';
            B := CompareStr(St2,St1);
          End;
          msManufacturer:
          Begin
            If Item.Prof <> Nil
             Then St1 := UpperCase(Item.Prof.Manufacturer)
             Else St1 := '';
            If Item1.Prof <> Nil
             Then St2 := UpperCase(Item1.Prof.Manufacturer)
             Else St2 := '';
            B := CompareStr(St2,St1);
          End;
          msYear:
          Begin
            If Item.Prof <> Nil
             Then Y1 := Item.Prof.Year
             Else Y1 := 0;
            If Item1.Prof <> Nil
             Then Y2 := Item1.Prof.Year
             Else Y2 := 0;
            If Y2 = Y1 Then B := 0 Else
             If Y2 < Y1 Then B := -1 Else B := 1;
          End;
          msDefaultSize:
          Begin
            If Item.Prof <> Nil
             Then Y1 := Item.Prof.DefaultSize
             Else Y1 := 0;
            If Item1.Prof <> Nil
             Then Y2 := Item1.Prof.DefaultSize
             Else Y2 := 0;
            If Y2 = Y1 Then B := 0 Else
             If Y2 < Y1 Then B := -1 Else B := 1;
          End;
          msController:
          Begin
            If Item.Prof <> Nil
             Then St1 := UpperCase(ContName[Item.Prof.Cont])
             Else St1 := '';
            If Item1.Prof <> Nil
             Then St2 := UpperCase(ContName[Item1.Prof.Cont])
             Else St2 := '';
            B := CompareStr(St2,St1);
          End;
          msScreenShot:
          Begin
            If Item1.ScreenShot = Item.ScreenShot Then B := 0
            Else If Item1.ScreenShot Then B := 1 Else B:= -1;
          End;
          msExtras:
          Begin
            St1 := Item.Extras;
            St2 := Item1.Extras;
            B   := CompareStr(St2,St1);
          End;
        End; // Case
        TestEqual := B;
      End; // TestEqual

    Begin
      B := TestEqual(Sort);
      S := msName;
      If Not SortAsc Then B := -B;
      While (B = 0) And (S <= msController) Do
      Begin
        If S <> Sort Then B := TestEqual(S);
        S := Succ(S);
      End; // While
      Equal := B;
    End; // Equal

  Begin
    Item := FileList[P];
    I    := P - 1;
    J    := R + 1;
    While True Do
    Begin
      Repeat
        Dec(J);
        Item1 := FileList[J];
      Until Equal(Item,Item1) <= 0;
      Repeat
        Inc(I);
        Item2 := FileList[I];
      Until Equal(Item,Item2) >= 0;
      If I < J Then
      Begin
        FileList[I] := Item1;
        FileList[J] := Item2;
      End
      Else
      Begin
        Partition := J;
        Exit;
      End;
    End; // While
  End; // Partition

Begin
  If P < R Then
  Begin
    Q := Partition(P,R);
    SortFileList(FileList,P,Q);
    SortFileList(FileList,Q + 1,R);
  End;
End; // TfrmAltMenu.SortFileList

Procedure TfrmAltMenu.GetProfileSettings;
Var
  I    : Integer;
  Item : TFileListItem;
  Cont : TController;
  MI   : TMenuInfo;

Begin
  I  := 0;
  While I < FileList.Count Do
  Begin
    Item := FileList[I];
    FindProfile(Item.Name,Cont,MI.Pos200,MI.Pos204,MI.Pos215,MI.Pos250,MI.Pos305,Item.Prof);
    If (Item.Prof <> Nil) And (Item.Prof.RealName <> '')
     Then Item.RNam := Item.Prof.RealName
     Else Item.RNam := Item.Name;
    Inc(I);
  End; // While
End; // TfrmAltMenu.GetProfileSettings

procedure TfrmAltMenu.FormShow(Sender: TObject);
Var
  S     : TSearchRec;
  Item  : TFileListItem;
  Z     : ZipDirEntry;
  I     : Integer;

begin
  Click             := False;
  LastClick         := -1;
  Caption           := 'PCAE ' + Version;

  // If there are any entries, get rid of them

  While FileList.Count > 0 Do
  Begin
    TFileListItem(FileList[0]).Free;
    FileList.Delete(0);
  End; // While

  // Locate all the .BIN and .PAL files

  If ParamCount > 0 Then Path := ParamStr(1) Else Path := Config.GamePath;
  If (Path <> '') And Not (Path[Length(Path)] In [':','\']) Then Path := Path + '\';

  // Locate all .BIN and .PAL files

  If FindFirst(Path + '*.BIN',faArchive,S) = 0 Then
  Repeat
    Item := TFileListItem.Create;
    FileList.Add(Item);
    Item.Name         := S.Name;
    Item.ZIPName      := '';
    Item.Size         := S.Size;
    Item.BoxFrontScan := False;
    Item.BoxBackScan  := False;
    Item.BoxSideScan  := False;
    Item.CartScan     := False;
    Item.Manual       := False;
    Item.Extras       := '';
  Until FindNext(S) <> 0;

  If FindFirst(Path + '*.PAL',faArchive,S) = 0 Then
  Repeat
    Item := TFileListItem.Create;
    FileList.Add(Item);
    Item.Name         := S.Name;
    Item.ZIPName      := '';
    Item.Size         := S.Size;
    Item.BoxFrontScan := False;
    Item.BoxBackScan  := False;
    Item.BoxSideScan  := False;
    Item.CartScan     := False;
    Item.Manual       := False;
    Item.Extras       := '';
  Until FindNext(S) <> 0;

  // Locate all .ZIP files, and locate all .BIN and .PAL files in those files

  If FindFirst(Path + '*.ZIP',faArchive,S) = 0 Then
  Repeat
    frmMain.ZipMaster1.ZipFilename := Path + S.Name;
    I := 0;
    While I < frmMain.ZipMaster1.ZipContents.Count Do
    Begin
      Z := PZipDirEntry(frmMain.ZipMaster1.ZipContents.Items[I])^;
      Z.FileName := UpperCase(Z.FileName);
      If (ExtractFileExt(Z.FileName) = '.BIN') Or
         (ExtractFileExt(Z.FileName) = '.PAL') Then
      Begin
        Item := TFileListItem.Create;
        FileList.Add(Item);
        Item.Name         := ExtractFileName(Z.FileName);
        Item.ZIPName      := Path + S.Name;
        Item.Size         := Z.UncompressedSize;
        Item.BoxFrontScan := False;
        Item.BoxBackScan  := False;
        Item.BoxSideScan  := False;
        Item.CartScan     := False;
        Item.Manual       := False;
        Item.Extras       := '';
      End;
      Inc(I);
    End; // While
  Until FindNext(S) <> 0;

  // Connect the profile settings to each entry

  GetProfileSettings;

  // Sort the file list

  SortFileList(FileList,0,FileList.Count - 1);

  // Show if there were any files found

  If FileList.Count = 0 Then Close
  Else
  Begin
    LoadStringGrid;
    InterfaceHandler.ActivateInterfaces;
    Game.Controller := OldController;
  End;
  Repaint;

  // Spawn a separate thread that will scan for screen shots, scans, and manuals

  ThreadDone := False;
  MyThread   := TMyThread.Create;
end;

procedure TfrmAltMenu.FormCreate(Sender: TObject);
begin
  MenuInfo.Title       := '';
  MenuInfo.FileName    := '';
  MenuInfo.ZipFileName := '';
  Sort                 := msName;
  SortAsc              := True;
  FileList             := TList.Create;
  Scaled               := False;
  sgMain               := TMyStringGrid.Create(Self);
  sgMain.ColCount      := 9;
  sgMain.FixedCols     := 0;
  sgMain.FixedRows     := 1;
  sgMain.Color         := clWindow;
  sgMain.FixedColor    := clBtnFace;
  sgMain.Options       := [goFixedVertLine,goFixedHorzLine,goVertLine,goHorzLine,goColSizing,goRowSelect,goThumbTracking];
  sgMain.GridLineWidth := 0;
  sgMain.Parent        := Panel3;
  sgMain.Align         := alClient;
  sgMain.OnDrawCell    := sgMainDrawCell;
  sgMain.OnDblClick    := sgMainDblClick;
  sgMain.OnKeyPress    := sgMainKeyPress;
  sgMain.OnMouseUp     := sgMainMouseUp;
//  sgMain.OnSelectCell  := sgMainSelectCell;
end;

procedure TfrmAltMenu.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  If Not ThreadDone Then
  Begin
    MyThread.Terminate;
    Repeat
      Application.ProcessMessages;
    Until ThreadDone;
  End;
  InterfaceHandler.DeactivateInterfaces;
end;

Procedure TfrmAltMenu.LoadStringGrid;
Var
  I     : Integer;
  Item  : TFileListItem;
  Count : Integer;

Begin

  // Important to do this because this can be called by FormCreate, before FileList
  // has been created

  If FileList <> Nil Then Count := FileList.Count Else Count := 0;
  sgMain.DefaultRowHeight := Canvas.TextHeight('Mg') + 4;

  sgMain.RowCount := Count + 1;
  I := 0;
  While I < Count Do
  Begin
    Item := FileList[I];
    If Config.MenuDisplayScheme In [dsRealNameLeft,dsRealNameCenter]
     Then sgMain.Cells[0,I + 1] := Item.RNam
     Else sgMain.Cells[0,I + 1] := Item.Name;
    Inc(I);
  End; // While

  // Load images

  LoadSelImages;
End; // TfrmAltMenu.LoadStringGrid

Procedure TfrmAltMenu.LoadSelImages;
Var
  I     : Integer;
  Item  : TFileListItem;
  St    : String;

Begin
  I := sgMain.Row - 1;
  If (I >= 0) And (I < FileList.Count) Then
  Begin
    Item := FileList[I];
    If (Item.Prof <> Nil) And (Item.Prof.RealName <> '')
     Then St := Item.Prof.RealName + '  [' + Item.Name + ']'
     Else St := Item.Name;
    St := St + '   ' + IntToStr(Item.Size) + ' bytes';
    sbMain.Panels[0].Text := St;
    LoadImages(Item.Name);
  End;
End; // TfrmAltMenu.LoadSelImages

procedure TfrmAltMenu.sgMainDrawCell(Sender: TObject; ACol, ARow: Integer;
  Rect: TRect; State: TGridDrawState);
Var
  F,B  : TColor;
  I    : Integer;
  Item : TFileListItem;
  St   : String;
  S    : Integer;
  W0   : Integer;
  W1   : Integer;

  Function GetString(Item: TFileListItem; Sort: TMenuSort): String;
  Begin
    Case Sort Of
      msName:
      Begin
        If Config.MenuDisplayScheme In [dsRealNameLeft,dsRealNameCenter]
         Then St := Item.RNam
         Else St := Item.Name;
      End;
      msSize: St := IntToStr(Item.Size);
      msType:
      Begin
        If Item.Prof <> Nil
         Then St := CartName[Item.Prof.Cart]
         Else St := '';
      End;
      msManufacturer:
      Begin
        If Item.Prof <> Nil
         Then St := Item.Prof.Manufacturer
         Else St := '';
      End;
      msYear:
      Begin
        If Item.Prof <> Nil
         Then St := IntToStr(Item.Prof.Year)
         Else St := '';
      End;
      msDefaultSize:
      Begin
        If Item.Prof <> Nil
         Then St := IntToStr(Item.Prof.DefaultSize)
         Else St := '';
      End;
      msController:
      Begin
        If Item.Prof <> Nil
         Then St := ContName[Item.Prof.Cont]
         Else St := '';
      End;
      msScreenShot:
      Begin
        If Item.ScreenShot Then St := 'Yes' Else St := 'No';
      End;
      msExtras:
      Begin
        St := Item.Extras;
      End;
    Else
      St := '';  
    End; // Case
    GetString := St;
  End; // GetString

  Procedure ChooseColor(Y: Integer);
  Begin
    If sgMain.Row = Y Then
    Begin
      F := clHighlightText;
      B := clHighlight;
    End
    Else
    Begin
      St := UpperCase(GetString(Item,Sort));
      Case Config.MenuColorScheme Of
      csGameType:
      Begin
        Case Item.Size Of
2048,4096: F := clBlack;
  8192: F := clTeal;
  8448: F := clRed;
 10495: F := clGreen;
 16384: F := clYellow;
        Else
          F := clNavy;
        End; { Case }
        If (Item.Size Mod 8448) = 0 Then F := clRed;
        B := clSilver;
      End;
      csAlphabetical:
      Begin
        If (St <> '') And ((Ord(St[1]) And 1) <> 0) Then
        Begin
          F := Config.MenuForeColor1;
          B := Config.MenuBackColor1;
        End
        Else
        Begin
          F := Config.MenuForeColor2;
          B := Config.MenuBackColor2;
        End;
      End;
      csEvery3:
      Begin
        If ((Y Div 3) And 1) <> 0 Then
        Begin
          F := Config.MenuForeColor1;
          B := Config.MenuBackColor1;
        End
        Else
        Begin
          F := Config.MenuForeColor2;
          B := Config.MenuBackColor2;
        End;
      End;
      csEvery4:
      Begin
        If ((Y Div 4) And 1) <> 0 Then
        Begin
          F := Config.MenuForeColor1;
          B := Config.MenuBackColor1;
        End
        Else
        Begin
          F := Config.MenuForeColor2;
          B := Config.MenuBackColor2;
        End;
      End;
      csEvery5:
      Begin
        If ((Y Div 5) And 1) <> 0 Then
        Begin
          F := Config.MenuForeColor1;
          B := Config.MenuBackColor1;
        End
        Else
        Begin
          F := Config.MenuForeColor2;
          B := Config.MenuBackColor2;
        End;
      End;
      csEvery6:
      Begin
        If ((Y Div 6) And 1) <> 0 Then
        Begin
          F := Config.MenuForeColor1;
          B := Config.MenuBackColor1;
        End
        Else
        Begin
          F := Config.MenuForeColor2;
          B := Config.MenuBackColor2;
        End;
      End;
      Else
        F := clBlack;
        B := clSilver;
      End; { Case }
    End;
  End; // ChooseColor

begin
  I := ARow - 1;
  If I = -1 Then
  Begin
    sgMain.Canvas.Font.Color  := Font.Color;
    sgMain.Canvas.Brush.Color := Color;
    sgMain.Canvas.FillRect(Rect);
    sgMain.Canvas.Pen.Color   := clBtnHighlight;
    sgMain.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgMain.Canvas.LineTo(Rect.Left,Rect.Top);
    sgMain.Canvas.LineTo(Rect.Right - 1,Rect.Top);
    sgMain.Canvas.Pen.Color   := clBtnShadow;
    sgMain.Canvas.MoveTo(Rect.Left,Rect.Bottom - 1);
    sgMain.Canvas.LineTo(Rect.Right - 1,Rect.Bottom - 1);
    sgMain.Canvas.LineTo(Rect.Right - 1,Rect.Top);

    sgMain.Canvas.Font.Name  := Font.Name;
    sgMain.Canvas.Font.Size  := Font.Size;
    sgMain.Canvas.Font.Style := Font.Style;
    St := MenuSortName[TMenuSort(ACol)];
    sgMain.Canvas.TextOut(Rect.Left + 2,Rect.Top + 2,St);
    If Integer(Sort) = ACol Then
    Begin
      S := (Rect.Bottom - Rect.Top) Div 4;
      If SortAsc Then
      Begin
        sgMain.Canvas.Pen.Color := clBtnShadow;
        sgMain.Canvas.MoveTo(Rect.Right - 4 * S,Rect.Bottom - 4);
        sgMain.Canvas.LineTo(Rect.Right - 3 * S,Rect.Top + 3);
        sgMain.Canvas.Pen.Color := clBtnHighlight;
        sgMain.Canvas.LineTo(Rect.Right - 2 * S,Rect.Bottom - 4);
        sgMain.Canvas.LineTo(Rect.Right - 4 * S,Rect.Bottom - 4);
      End
      Else
      Begin
        sgMain.Canvas.Pen.Color := clBtnHighlight;
        sgMain.Canvas.MoveTo(Rect.Right - 2 * S,Rect.Top + 3);
        sgMain.Canvas.LineTo(Rect.Right - 3 * S,Rect.Bottom - 4);
        sgMain.Canvas.Pen.Color := clBtnShadow;
        sgMain.Canvas.LineTo(Rect.Right - 4 * S,Rect.Top + 3);
        sgMain.Canvas.LineTo(Rect.Right - 2 * S,Rect.Top + 3);
      End;
    End;
  End
  Else
  If (I >= 0) And (I < FileList.Count) Then
  Begin
    Item := FileList[I];
    St   := GetString(Item,TMenuSort(ACol));
    ChooseColor(ARow);
    sgMain.Canvas.Font.Color  := F;
    sgMain.Canvas.Brush.Color := B;
    sgMain.Canvas.FillRect(Rect);
    sgMain.Canvas.Font.Name  := Font.Name;
    sgMain.Canvas.Font.Size  := Font.Size;
    sgMain.Canvas.Font.Style := Font.Style;
    St := GetString(Item,TMenuSort(ACol));
(*
    St := '';
    Case ACol Of
   0: Begin
        If Config.MenuDisplayScheme In [dsRealNameLeft,dsRealNameCenter]
         Then St := Item.RNam
         Else St := Item.Name;
      End;
   1: St := IntToStr(Item.Size);
   2: If Item.Prof <> Nil Then St := CartName[Item.Prof.Cart];
   3: If Item.Prof <> Nil Then St := Item.Prof.Manufacturer;
   4: If (Item.Prof <> Nil) And (Item.Prof.Year <> 0) Then St := IntToStr(Item.Prof.Year);
   5: If (Item.Prof <> Nil) And (Item.Prof.DefaultSize <> 0) Then St := IntToStr(Item.Prof.DefaultSize);
   6: If Item.Prof <> Nil Then St := ContName[Item.Prof.Cont];
    End; // Case
*)
    If Config.MenuDisplayScheme <> dsRealNameCenter
     Then sgMain.Canvas.TextOut(Rect.Left + 2,Rect.Top + 2,St)
     Else
     Begin
       W0 := sgMain.Canvas.TextWidth(St);
       W1 := Rect.Right - Rect.Left - 4;
       If W0 <= W1
        Then sgMain.Canvas.TextOut(Rect.Left + 2 + ((W1 - W0) Div 2),Rect.Top + 2,St)
        Else sgMain.Canvas.TextOut(Rect.Left + 2,Rect.Top + 2,St)
     End;

     If (ACol = sgMain.ColCount - 1) And (gdSelected In State) And ThreadDone Then
     Begin

       // Load images

       I := ARow - 1;
       If (I >= 0) And (I < FileList.Count) Then
       Begin
         Item := FileList[I];
         If (Item.Prof <> Nil) And (Item.Prof.RealName <> '')
          Then St := Item.Prof.RealName + '  [' + Item.Name + ']'
          Else St := Item.Name;
         St := St + '   ' + IntToStr(Item.Size) + ' bytes';
         sbMain.Panels[0].Text := St;
         Application.ProcessMessages;
         LoadImages(Item.Name);
       End;
     End;

//    sgMain.Canvas.TextOut(Rect.Left + 2,Rect.Top + 2,St);
  End;
end;

procedure TfrmAltMenu.sgMainDblClick(Sender: TObject);
Var
  I    : Integer;
  Item : TFileListItem;

begin
  If Not Click Then
  Begin
    I := sgMain.Row - 1;
    If (I >= 0) And (I < FileList.Count) And (LastClick >= 0) Then
    Begin
      Item := FileList[I];
      ProcessChosenCart(#13,Item);
      Close;
    End;
  End;
end;

procedure TfrmAltMenu.FormResize(Sender: TObject);
Var I,J: Integer;
begin
  J := 0;
  For I := 0 To sgMain.ColCount - 2 Do Inc(J,sgMain.ColWidths[I] + sgMain.GridLineWidth);
  I := sgMain.Width - J - 1;
  If I < 4 Then I := 4;
  sgMain.ColWidths[sgMain.ColCount - 1] := I;
  btnManual.Left := ClientWidth - btnManual.Width - 4;
end;

Procedure TfrmAltMenu.OpenFile(Const FileName: String; Img: TImage; ZIP: Boolean);
Begin
  Try
    Img.Picture.LoadFromFile(FileName);
    If Not Img.Stretch Then
    Begin
      Img.Width  := Img.Picture.Width;
      Img.Height := Img.Picture.Height;
    End;
    If ZIP Then DeleteFile(FileName);
  Except
    On EInvalidGraphic Do Img.Picture.Graphic := Nil;
  End;
End; // TfrmAltMenu.OpenFile

Procedure TfrmAltMenu.ClearImage(Var Img: TImage; Stretch: Boolean);
Var R: TRect;
Begin
  R.Left   := Img.Left;
  R.Top    := Img.Top;
  R.Right  := Img.Width;
  R.Bottom := Img.Height;
  Img.Free;
  Img := TImage.Create(Self);
  Img.Parent      := Panel2;
  Img.Left        := R.Left;
  Img.Top         := R.Top;
  Img.Width       := R.Right;
  Img.Height      := R.Bottom;
  Img.Stretch     := Stretch;
  Img.Visible     := True;
  Img.Enabled     := True;
  Img.AutoSize    := False;
  Img.Transparent := False;
End; // TfrmAltMenu.ClearImage

Procedure TfrmAltMenu.LoadImages(FileName: String);
Var
  St  : String;
  I   : Integer;
  SS  : String;
  BF  : String;
  BB  : String;
  BS  : String;
  CS  : String;
  ZIP : Boolean;

Begin
  ClearImage(imgScreenShot,False);
  ClearImage(imgBoxFrontScan,True);
  ClearImage(imgBoxBackScan,True);
  ClearImage(imgBoxSideScan,True);
  ClearImage(imgCartScan,True);
  St := FileName;
//  I  := Pos('.',St);
  I := Length(St);
  While (St[I] <> '.') And (I > 0) Do Dec(I);
  If I <> 0 Then St := Copy(St,1,I - 1);
  SS := Config.ScreenShotPath;
  BF := Config.BoxFrontScanPath;
  BB := Config.BoxBackScanPath;
  BS := Config.BoxSideScanPath;
  CS := Config.CartScanPath;
  If (SS <> '') And Not (SS[Length(SS)] In [':','\']) Then SS := SS + '\';
  If (BF <> '') And Not (BF[Length(BF)] In [':','\']) Then BF := BF + '\';
  If (BB <> '') And Not (BB[Length(BB)] In [':','\']) Then BB := BB + '\';
  If (BS <> '') And Not (BS[Length(BS)] In [':','\']) Then BS := BS + '\';
  If (CS <> '') And Not (CS[Length(CS)] In [':','\']) Then CS := CS + '\';

  If FileExistsZip(SS + St + '.BMP',True,ZIP) Then OpenFile(SS + St + '.BMP',imgScreenShot,ZIP) Else
   If FileExistsZip(SS + St + '.JPG',True,ZIP) Then OpenFile(SS + St + '.JPG',imgScreenShot,ZIP);

  imgBoxFrontScan.Top := imgScreenShot.Top + imgScreenShot.Height + 8;
  imgBoxBackScan.Top  := imgBoxFrontScan.Top;
  imgBoxSideScan.Top  := imgBoxFrontScan.Top;
  Application.ProcessMessages;

  If FileExistsZip(BF + St + '.BMP',True,ZIP) Then OpenFile(BF + St + '.BMP',imgBoxFrontScan,ZIP) Else
   If FileExistsZip(BF + St + '.JPG',True,ZIP) Then OpenFile(BF + St + '.JPG',imgBoxFrontScan,ZIP);

  imgCartScan.Top     := imgBoxFrontScan.Top + imgBoxFrontScan.Height + 8;
  Application.ProcessMessages;

  If FileExistsZip(BB + St + '.BMP',True,ZIP) Then OpenFile(BB + St + '.BMP',imgBoxBackScan,ZIP) Else
   If FileExistsZip(BB + St + '.JPG',True,ZIP) Then OpenFile(BB + St + '.JPG',imgBoxBackScan,ZIP);

  Application.ProcessMessages;

  If FileExistsZip(BS + St + '.BMP',True,ZIP) Then OpenFile(BS + St + '.BMP',imgBoxSideScan,ZIP) Else
   If FileExistsZip(BS + St + '.JPG',True,ZIP) Then OpenFile(BS + St + '.JPG',imgBoxSideScan,ZIP);

  Application.ProcessMessages;

  If FileExistsZip(CS + St + '.BMP',True,ZIP) Then OpenFile(CS + St + '.BMP',imgCartScan,ZIP) Else
   If FileExistsZip(CS + St + '.JPG',True,ZIP) Then OpenFile(CS + St + '.JPG',imgCartScan,ZIP);

//  imgBoxFrontScan.Top := imgScreenShot.Top + imgScreenShot.Height + 8;
//  imgBoxBackScan.Top  := imgBoxFrontScan.Top;
//  imgBoxSideScan.Top  := imgBoxFrontScan.Top;
//  imgCartScan.Top     := imgBoxFrontScan.Top + imgBoxFrontScan.Height + 8;
End; // TfrmAltMenu.LoadImages

procedure TfrmAltMenu.sgMainMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Var
  I,J   : Integer;
  Item  : TFileListItem;
//  St    : String;
  Count : Integer;
  MI    : TMenuInfo;
  Found : Boolean;
  X0    : Integer;

begin
  Click := True;
  If FileList <> Nil Then Count := FileList.Count Else Count := 0;
  Case Button Of
  mbLeft: Begin

            // Important to do this because this can be called by FormCreate, before FileList
            // has been created

            I  := (Y Div (sgMain.DefaultRowHeight + sgMain.GridLineWidth)) - 2 + sgMain.TopRow;
            LastClick := I;
{            If (I >= 0) And (I < Count) And (Y >= (sgMain.DefaultRowHeight + sgMain.GridLineWidth)) Then
            Begin
              Item := FileList[I];
              If (Item.Prof <> Nil) And (Item.Prof.RealName <> '')
               Then St := Item.Prof.RealName + '  [' + Item.Name + ']'
               Else St := Item.Name;
              St := St + '   ' + IntToStr(Item.Size) + ' bytes';
              sbMain.Panels[0].Text := St;
              LoadImages(Item.Name);
            End
            Else If Y < (sgMain.DefaultRowHeight + sgMain.GridLineWidth) Then
}
            If Y < (sgMain.DefaultRowHeight + sgMain.GridLineWidth) Then
            Begin
              Found := False;
              J     := 0;
              X0    := 0;
              While (J < sgMain.ColCount) And Not Found Do
              Begin
                If (X >= X0) And (X < X0 + sgMain.ColWidths[J]) Then Found := True Else
                Begin
                  Inc(X0,sgMain.ColWidths[J]);
                  Inc(J);
                End;
              End; // While
              If Found Then
              Begin
                If Integer(Sort) = J Then
                Begin
                  SortAsc := Not SortAsc;
                End
                Else
                Begin
                  SortAsc := True;
                  Sort    := TMenuSort(J);
                End;
                SortFileList(FileList,0,FileList.Count - 1);
                LoadStringGrid;
                Repaint;
              End;
            End;
          End;
 mbRight: Begin
            I  := (Y Div (sgMain.DefaultRowHeight + sgMain.GridLineWidth)) - 2 + sgMain.TopRow;
            If (I >= 0) And (I < Count) Then
            Begin
              MI   := MenuInfo;
              Item := FileList[I];
              MenuInfo.FileName := Path + Item.Name;
              MenuInfo.ZipFileName := Item.ZIPName;
              MenuInfo.Title := Item.RNam;
              OldController  := Game.Controller;
              FindProfile(Item.Name,MenuInfo.Cont,MenuInfo.Pos200,MenuInfo.Pos204,
                     MenuInfo.Pos215,MenuInfo.Pos250,MenuInfo.Pos305,MenuInfo.ProfileRec);
              If MenuInfo.Cont <> crUnknown Then Game.Controller := MenuInfo.Cont;
              frmProfileSettings.ShowModal;
              MenuInfo := MI;
              Game.Controller := OldController;
              GetProfileSettings;
              SortFileList(FileList,0,FileList.Count - 1);
              LoadStringGrid;
              sgMain.Repaint;
            End;
          End;
  End; // Case
  Click := False;
//  Application.ProcessMessages;
end;

procedure TfrmAltMenu.sgMainKeyPress(Sender: TObject; var Key: Char);
Var
  I    : Integer;
  Item : TFileListItem;

begin
  Case UpCase(Key) Of
    #13,#27,'A','G','R','P','M','T','2','3','V','O':
    Begin
      If UpCase(Key) In [#13,'A','G','R','P','M','T','2','3','V','O'] Then
      Begin
        I := sgMain.Row - 1;
        If (I >= 0) And (I < FileList.Count) Then
        Begin
          Item := FileList[I];
          ProcessChosenCart(Key,Item);
        End;
      End
      Else MenuInfo.FileName := '';
      Close;
    End;
  End; // Case
end;

Procedure TfrmAltMenu.ProcessChosenCart(Ch: Char; Item: TFileListItem);
Var
  St   : String;
  J    : Integer;
  Code : Integer;

Begin
  MenuInfo.FileName    := Path + Item.Name;
  MenuInfo.ZipFileName := Item.ZIPName;
  MenuInfo.Title       := Item.RNam;
  If Ch = #13 Then
  Begin
    OldController := Game.Controller;
    Ch := MenuKey[FindProfile(Item.Name,MenuInfo.Cont,MenuInfo.Pos200,MenuInfo.Pos204,
                  MenuInfo.Pos215,MenuInfo.Pos250,MenuInfo.Pos305,MenuInfo.ProfileRec)];
    If MenuInfo.Cont <> crUnknown Then Game.Controller := MenuInfo.Cont;
  End
  Else
  Begin
    FindProfile(Item.Name,MenuInfo.Cont,MenuInfo.Pos200,MenuInfo.Pos204,
                MenuInfo.Pos215,MenuInfo.Pos250,MenuInfo.Pos305,MenuInfo.ProfileRec);
  End;
  If Ch In ['T','A','2','R','P','M','G','V','O'] Then SetBankInfo(Ch,Game)
  Else
  Begin
    Case Ch Of
'3': Begin                               { 32-in-1 }
      Game.Cart := ct32In1;
      St := InputBox('Set game title','Enter game title:',IntToStr(Game.MegaBoyNum));
      Val(St,J,Code);
      If (J >= 0) And (J <= 31) Then Game.MegaBoyNum := J;
    End;
    Else
      Game.Cart := ct4k;
      If Item.Size = 8192  Then SetBankInfo('8',Game);        { Standard 8k }
      If Item.Size = 10495 Then SetBankInfo('2',Game);        { Pitfall II }
      If (Item.Size Mod 8448) = 0 Then SetBankInfo('S',Game); { Starpath }
      If Item.Size = 12288 Then SetBankInfo('C',Game);        { CBS RAM-Plus }
      If Item.Size = 16384 Then SetBankInfo('6',Game);        { Standard 16k }
    End; { Case }
  End;
End; // TfrmAltMenu.ProcessChosenCart

procedure TfrmAltMenu.FormDestroy(Sender: TObject);
begin
  While FileList.Count > 0 Do
  Begin
    TFileListItem(FileList[0]).Free;
    FileList.Delete(0);
  End; // While
  FileList.Free;
end;
{
procedure TfrmAltMenu.sgMainSelectCell(Sender: TObject; ACol,
  ARow: Integer; var CanSelect: Boolean);
Var
  I    : Integer;
  Item : TFileListItem;
  St   : String;

begin

  // Load images

  I := ARow - 1;
  If (I >= 0) And (I < FileList.Count) Then
  Begin
    Item := FileList[I];
    If (Item.Prof <> Nil) And (Item.Prof.RealName <> '')
     Then St := Item.Prof.RealName + '  [' + Item.Name + ']'
     Else St := Item.Name;
    St := St + '   ' + IntToStr(Item.Size) + ' bytes';
    sbMain.Panels[0].Text := St;
    LoadImages(Item.Name);
  End;
end;
}
procedure TfrmAltMenu.Splitter1Moved(Sender: TObject);
begin
  FormResize(Self);
end;

procedure TfrmAltMenu.btnManualClick(Sender: TObject);
Var
  MP     : String;
  St     : String;
  I      : Integer;
  Item   : TFileListItem;
  ZIP    : Boolean;
  Manual : String;

  Procedure OpenManual(FileName: String; RTF: Boolean);
  Var Flags: OLEVariant;
  Begin
//    frmManual.reManual.PlainText := Not RTF;
//    frmManual.reManual.Lines.Clear;
//    frmManual.reManual.Lines.LoadFromFile(FileName);
    Flags  := 0;
    Manual := ExtractFileName(FileName);
    frmManual.wbManual.Navigate('file://' + FileName, Flags, Flags, Flags, Flags);
    frmManual.ShowModal;
  End; // OpenManual

begin
  I := sgMain.Row - 1;
  If (I >= 0) And (I < FileList.Count) Then
  Begin
    Item := FileList[I];
    St := RemoveFileExt(Item.Name);

    MP := Config.ManualPath;
    If (MP <> '') And Not (MP[Length(MP)] In [':','\']) Then MP := MP + '\';

         If FileExistsZip(MP + St + '.TXT',True,ZIP)  Then OpenManual(MP + St + '.TXT',False)
    Else If FileExistsZip(MP + St + '.RTF',True,ZIP)  Then OpenManual(MP + St + '.RTF',True)
    Else If FileExistsZip(MP + St + '.PDF',True,ZIP)  Then OpenManual(MP + St + '.PDF',True)
    Else If FileExistsZip(MP + St + '.HTM',True,ZIP)  Then OpenManual(MP + St + '.HTM',True)
    Else If FileExistsZip(MP + St + '.HTML',True,ZIP) Then OpenManual(MP + St + '.HTML',True);
    If ZIP Then DeleteFile(Manual);
  End;
end;

end.

// ----------------------------------------------------------------------
// PCAE and PCAEWin - PC Atari Emulator - Atari 2600 emulator
// Copyright (C) 2000 John Dullea
//
//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// ----------------------------------------------------------------------
