unit uArcadeGamesFilter;

interface

uses
  Windows, Messages, Classes, Graphics, Controls, Forms,
  Buttons, VirtualTrees, SysUtils, StdCtrls, ExtCtrls, IniFiles, ImgList,
  GR32_Image;

type
  pFilterInfo = ^TFilterInfo;
  TFilterInfo = packed record
    aFilterImageIndex: Integer;
    aFilterParent: Integer;
    aFilterDescription: String;
    aFilterName: String;
    aFitterIconLoaded: Boolean;
  end;

type
  TFormArcadeGamesFilter = class(TForm)
    ButtonCancel: TButton;
    ButtonApply: TButton;
    GamesFilter1: TVirtualStringTree;
    LabelSelectedNode: TLabel;
    LabelGameDescription: TLabel;
    IL_ArcadeFilterMain_Small: TImageList;
    TopImage: TImage32;
    ImageFilterIcon: TImage;
    IL_ArcadeFilterMain_Large: TImageList;
    ButtonFilterInfo: TButton;
    procedure GamesFilter1FreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure GamesFilter1GetHint(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex;
      var LineBreakStyle: TVTTooltipLineBreakStyle;
      var HintText: WideString);
    procedure GamesFilter1GetImageIndex(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
      var Ghosted: Boolean; var ImageIndex: Integer);
    procedure GamesFilter1GetText(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
      var CellText: WideString);
    procedure GamesFilter1IncrementalSearch(Sender: TBaseVirtualTree;
      Node: PVirtualNode; const SearchText: WideString;
      var Result: Integer);
    procedure ButtonCancelClick(Sender: TObject);
    procedure ButtonApplyClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure GamesFilter1Change(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure FormKeyPress(Sender: TObject; var Key: Char);
    procedure FormShow(Sender: TObject);
    procedure ButtonFilterInfoClick(Sender: TObject);
  private
    { Private declarations }
    CurrentNode: PVirtualNode;
    procedure MountFiltersList;
  public
    { Public declarations }
  end;

var
  FormArcadeGamesFilter: TFormArcadeGamesFilter;

implementation

uses uMain, uCommon;

{$R *.dfm}

procedure TFormArcadeGamesFilter.MountFiltersList;
var
  Node, ParentNode: PVirtualNode;
  Data: pFilterInfo;
  filters_file: TMemIniFile;
  tmpList, tmpList2: THashedStringList;
  Loop, Loop2: Integer;
begin
  Application.ProcessMessages;
  case FileExists(FormMain.FrontendPath+'ini_files\mame_filters.ini') of
    True:
      begin
        try
          filters_file:= TMemIniFile.Create(FormMain.FrontendPath+'ini_files\mame_filters.ini');
          tmpList:= THashedStringList.Create;
          filters_file.ReadSectionValues('main', tmpList);
        except
          FreeAndNil(filters_file);
          FreeAndNil(tmpList);
        end;
      end;
    False:
      begin
        GenerateMessage('File not Found', Format('The file "%s" was not found. Cannot change filter!',
                        [FormMain.FrontendPath+'ini_files\mame_filters.ini']), 2);
        Close;
        Exit;
      end;
  end;

  if (not Assigned(tmpList)) or (tmpList.Count = 0) then
     begin
       GenerateMessage('Error', 'Main filter list is empty. Impossible to continue. Aborting...', 2);
       FreeAndNil(filters_file);
       FreeAndNil(tmpList);
       Close;
       Exit;
     end;

  FormMain.AddDefaultIcons('reserved.ico', FormMain.GetZipFolderFull(32), IL_ArcadeFilterMain_Small);
  FormMain.AddDefaultIcons('reserved.ico', FormMain.GetZipFolderFull(32), IL_ArcadeFilterMain_Large);

  tmpList2:= THashedStringList.Create;

  GamesFilter1.NodeDataSize:= SizeOf(TFilterInfo);
  GamesFilter1.RootNodeCount:= 0;
  GamesFilter1.BeginUpdate;
  for Loop:=0 to tmpList.Count-1 do
  begin
    Node:= GamesFilter1.AddChild(nil);
    Data:= GamesFilter1.GetNodeData(Node);
    Data.aFilterParent:= -1;
    Data.aFilterName:= tmpList.Names[Loop];
    if Data.aFilterName <> 'favorites' then
       Data.aFilterDescription:= tmpList.ValueFromIndex[Loop]
    else
       Data.aFilterDescription:= tmpList.ValueFromIndex[Loop]+'   [Ctrl+F3 toggle ON/OFF]';
    Data.aFitterIconLoaded:= False;
    if filters_file.SectionExists(tmpList.Names[Loop]) then
       begin
         // add sub-filters
         tmpList2.Clear;
         filters_file.ReadSectionValues(tmpList.Names[Loop], tmpList2);
         if tmpList2.Count > 0 then
            begin
              ParentNode:= Node;
              for Loop2:=0 to tmpList2.Count-1 do
              begin
                Node:= GamesFilter1.AddChild(ParentNode);
                Data:= GamesFilter1.GetNodeData(Node);
                Data.aFilterParent:= ParentNode.Index;
                Data.aFilterDescription:= tmpList2.ValueFromIndex[Loop2];
                Data.aFilterName:= tmpList2.Names[Loop2];
              end;
              GamesFilter1.Expanded[ParentNode]:= True;
            end
         else
            GenerateMessage('Warning', Format('A section named "[%s]" was found with an empty list. '+
                            'No sub-filters will be added for "%s".', [tmpList.Names[Loop],
                            tmpList.ValueFromIndex[Loop]]), 2);
        end;
  end;
  GamesFilter1.EndUpdate;
  FreeAndNil(tmpList);
  FreeAndNil(tmpList2);
  FreeAndNil(filters_file);
  FormArcadeGamesFilter.Tag:= 1;
  if FormMain.SelectedFilterName <> '' then
     begin
       Node:= GamesFilter1.GetFirst;
       repeat
         Data:= GamesFilter1.GetNodeData(Node);
         if Data.aFilterName <> FormMain.SelectedFilterName then
            Node:= GamesFilter1.GetNextVisible(Node);
       until (not Assigned(Node)) or (Data.aFilterName = FormMain.SelectedFilterName);
     end;
  if Node = nil then
     Node:= GamesFilter1.GetFirst;
  GamesFilter1.Selected[Node]:= True;
  GamesFilter1.FocusedNode:= Node;
  GamesFilter1.ScrollIntoView(Node, True);
  GamesFilter1.GetNodeData(Node);
  IL_ArcadeFilterMain_Large.GetIcon(Data.aFilterImageIndex, ImageFilterIcon.Picture.Icon);
end;

procedure TFormArcadeGamesFilter.GamesFilter1FreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: pFilterInfo;
begin
  Data:= GamesFilter1.GetNodeData(Node);
  Finalize(Data^);
end;

procedure TFormArcadeGamesFilter.GamesFilter1GetHint(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex;
  var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: WideString);
var
  Data: pFilterInfo;
begin
  Data:= GamesFilter1.GetNodeData(Node);
  if Column = 0 then
     HintText:= Data.aFilterDescription;
end;

procedure TFormArcadeGamesFilter.GamesFilter1GetImageIndex(
  Sender: TBaseVirtualTree; Node: PVirtualNode; Kind: TVTImageKind;
  Column: TColumnIndex; var Ghosted: Boolean; var ImageIndex: Integer);
var
  Data: pFilterInfo;
  tempFolder: String;
begin
  if Kind in [ikNormal, ikSelected] then
     begin
       if Column = 0 then
          begin
            Data:= Sender.GetNodeData(Node);
            if not Data.aFitterIconLoaded then
               begin
                 tempFolder:= FormMain.GetZipFolderFull(32)+'arcade_filters\';
                 case FileExists(tempFolder+Data.aFilterName+'.ico') of
                   True:
                     begin
                       FormMain.AddDefaultIcons(Data.aFilterName+'.ico', tempFolder, IL_ArcadeFilterMain_Small);
                       FormMain.AddDefaultIcons(Data.aFilterName+'.ico', tempFolder, IL_ArcadeFilterMain_Large);
                       Data.aFilterImageIndex:= IL_ArcadeFilterMain_Small.Count-1;
                     end;
                   False: Data.aFilterImageIndex:= 0;
                 end;
                 Data.aFitterIconLoaded:= True;
               end;
            ImageIndex:= Data.aFilterImageIndex;
          end;
     end;
end;

procedure TFormArcadeGamesFilter.GamesFilter1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  Data: pFilterInfo;
begin
  Data:= Sender.GetNodeData(Node);
  if Column = 0 then
     CellText:= Data.aFilterDescription;
end;

procedure TFormArcadeGamesFilter.GamesFilter1IncrementalSearch(
  Sender: TBaseVirtualTree; Node: PVirtualNode;
  const SearchText: WideString; var Result: Integer);
var
  StringsText,
  EntryText: String;
  Data: pFilterInfo;
begin
  StringsText:= SearchText;
  Data:= Sender.GetNodeData(Node);
  EntryText:= Data.aFilterDescription;
  Result := AnsiStrLIComp(PChar(StringsText), PChar(EntryText), Length(StringsText));
end;

procedure TFormArcadeGamesFilter.ButtonCancelClick(Sender: TObject);
begin
  LabelSelectedNode.Caption:= 'cancel';
  Close;
end;

procedure TFormArcadeGamesFilter.ButtonApplyClick(Sender: TObject);
begin
  Close;
end;

procedure TFormArcadeGamesFilter.FormCloseQuery(Sender: TObject;
  var CanClose: Boolean);
begin
  FormMain.ClearTreeView(GamesFilter1);
  IL_ArcadeFilterMain_Small.Clear;
end;

procedure TFormArcadeGamesFilter.GamesFilter1Change(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: pFilterInfo;
begin
  if (Sender.SelectedCount = 1) and (Sender.Visible) then
     begin
       if CurrentNode <> Node then
          CurrentNode:= Node;
       Data:= Sender.GetNodeData(CurrentNode);
       LabelSelectedNode.Caption:= Data.aFilterName;
       IL_ArcadeFilterMain_Large.GetIcon(Data.aFilterImageIndex, ImageFilterIcon.Picture.Icon);
     end;
end;

procedure TFormArcadeGamesFilter.FormKeyPress(Sender: TObject; var Key: Char);
begin
  {if (FormPreferences.HotRod.Checked) or (FormPreferences.XArcade.Checked) or (FormPreferences.SlikStik.Checked)
     or (FormPreferences.Devastator2.Checked) then
     begin
       if (Key = 'S') or (Key = 's') then
          ButtonYes.Click
       else
       if (Key = 'Q') or (Key = 'q') then
          ButtonNo.Click; // ClickButtonNo
     end
  else
     begin}
       if Key = #13 then
          ButtonApply.Click
       else
       if Key = #27 then
          ButtonCancel.Click;
     //end;
end;

procedure TFormArcadeGamesFilter.FormShow(Sender: TObject);
begin
  FormMain.LoadTopBar(TopImage, 'arcade_filter.png');
  FormMain.SetAlphaBlendTreeView(GamesFilter1);
  if FormArcadeGamesFilter.Tag = 0 then
     MountFiltersList;
end;

procedure TFormArcadeGamesFilter.ButtonFilterInfoClick(Sender: TObject);
var
  Data: pFilterInfo;
begin
  if GamesFilter1.SelectedCount = 1 then
     begin
       Data:= GamesFilter1.GetNodeData(CurrentNode);
       if Data.aFilterName = 'classic' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+
                          'All games except Neo-Geo.', 2)
       else
       if Data.aFilterName = 'chd' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'All games that have a .chd file.', 2)
       else
       if Data.aFilterName = 'irem' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Irem" '+
                          'that use the following drivers:'+#13#10+
                          'm62.c, m72.c, m90.c, m92.c, m107.c, mpatrol.c, vigilant.c', 2)
       else
       if Data.aFilterName = 'midway' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Midway" '+
                          'that use the following drivers:'+#13#10+
                          'midtunit.c, midvunit.c, midwunit.c, midxunit.c, midyunit.c, midzeus.c', 2)
       else
       if Data.aFilterName = 'capcom' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Capcom" category.', 2)
       else
       if Data.aFilterName = 'capcom_oldschool' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Capcom" '+
                          'that use the following drivers:'+#13#10+
                          'gng.c, gunsmoke.c, higemaru.c, sonson.c, commando.c, tigeroad.c', 2)
       else
       if Data.aFilterName = 'sega' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Sega" category.', 2)
       else
       if Data.aFilterName = 'system16' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This system use the following drivers:'+#13#10+
                          'system16.c, segahang.c, segaorun.c, segas16a.c, segas16b.c', 2)
       else
       if Data.aFilterName = 'system18' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This system use the following drivers:'+#13#10+
                          'system18.c, segas18.c', 2)
       else
       if Data.aFilterName = 'system32' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This system use the following drivers:'+#13#10+
                          'system32.c, segas32.c', 2)
       else
       if Data.aFilterName = 'segaxybd' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This system use the following drivers:'+#13#10+
                          'segaxbd.c, segaybd.c', 2)
       else
       if Data.aFilterName = 'megatech_megaplay' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This system use the following drivers:'+#13#10+
                          'megatech.c, megaplay.c', 2)
       else
       if Data.aFilterName = 'konami' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Konami" category.', 2)
       else
       if Data.aFilterName = 'konami_oldschool1' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Konami" '+
                          'that use the following drivers:'+#13#10+
                          'tmnt.c, simpsons.c, moo.c, parodius.c, xexex.c', 2)
       else
       if Data.aFilterName = 'konami_oldschool2' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Konami" '+
                          'that use the following drivers:'+#13#10+
                          'trackfld.c, gyruss.c, hyperspt.c, yiear.c, pingpong.c, gberet.c, '+
                          'hcastle.c, contra.c, thunderx.c, 88games.c, nemesis.c, twin16.c, '+
                          'gradius3.c, pooyan.c', 2)
       else
       if Data.aFilterName = 'taito' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Taito" category.', 2)
       else
       if Data.aFilterName = 'taito_misc' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter contain multiple systems from "Taito" '+
                          'that use the following drivers:'+#13#10+
                          'taito_b.c, taito_h.c, taito_l.c, taito_x.c, taito_z.c, '+
                          'taitojc.c, taitosj.c', 2)
       else
       if Data.aFilterName = 'taito_oldschool' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Taito" '+
                          'that use the following drivers:'+#13#10+
                          'halleys.c, tsamurai.c, fastfred.c, superqix.c, flstory.c, '+
                          'slapfght.c, tnzs.c, arkanoid.c, bublbobl.c, rainbow.c, lkage.c', 2)
       else
       if Data.aFilterName = 'namco' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Namco" category.', 2)
       else
       if Data.aFilterName = 'namcos11' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter contain multiple systems from "Namco" '+
                          'that use the following drivers:'+#13#10+
                          'namcos10.c, namcos11.c', 2)
       else
       if Data.aFilterName = 'namcos22' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter contain multiple systems from "Namco" '+
                          'that use the following drivers:'+#13#10+
                          'namcos22.c, namcos23.c', 2)
       else
       if Data.aFilterName = 'namco_misc' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter contain multiple systems from "Namco" '+
                          'that use the following drivers:'+#13#10+
                          'namcona1.c, namconb1.c, namcond1.c, namcofl.c', 2)
       else
       if Data.aFilterName = 'namco_oldschool' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Namco" '+
                          'that use the following drivers:'+#13#10+
                          'galaga.c, mappy.c, gaplus.c, baraduke.c, rallyx.c, '+
                          'pacland.c, pacman.c, polepos.c', 2)
       else
       if Data.aFilterName = 'atari' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Atari" category.', 2)
       else
       if Data.aFilterName = 'atari_misc' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter contain multiple systems from "Atari" '+
                          'that use the following drivers:'+#13#10+
                          'atarig1.c, atarig42.c, atarigt.c, atarigx2.c', 2)
       else
       if Data.aFilterName = 'atari_oldschool' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Atari" '+
                          'that use the following drivers:'+#13#10+
                          'centiped.c, ccastles.c, irobot.c, missile.c, arcadecl.c, badlands.c, '+
                          'blstroid.c, gauntlet.c, harddriv.c, klax.c, atetris.c, toobin.c, xybots.c', 2)
       else
       if Data.aFilterName = 'nintendo' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This filter enable all sub-filters in the "Nintendo" category.', 2)
       else
       if Data.aFilterName = 'nintendo_oldschool' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'This is a custom compilation of games from "Nintendo" '+
                          'that use the following drivers:'+#13#10+
                          'dkong.c, popeye.c, punchout.c, mario.c', 2)
       else
       if Data.aFilterName = 'favorites' then
          GenerateMessage('Filter Info', Data.aFilterDescription+#13#10+#13#10+
                          'Show a list of favorite games created by the user.', 2);
     end;
  GamesFilter1.SetFocus;
end;

end.
