unit uMain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  Menus, ComCtrls, ToolWin, ExtCtrls, IniFiles, StdCtrls, Buttons, ImgList,
  FileCtrl, GraphicEx, GR32_Image, GR32, GR32_RangeBars, GR32_Resamplers,
  ShellAPI, CommCtrl, ZipForge, JPEG, Themes, fmodtypes, BarMenus,
  VirtualTrees, URLMon, ExtDlgs, OleCtrls, SHDocVw,
  madExceptVcl, unitExIcon, BcDrawModule, BcCustomDrawModule, BcRectUtilities,
  StrUtils, uCommon, CoolTrayIcon;

type
  TZipForgeFriend = class(TZipForge);

type
  TGameInfo = record
    eImageIndex: Integer;
    eParent: Integer;
    eROMIdentification: Integer;
    eMediaType: ShortInt; // -1 - Unknown; 0 - ROM; 1 - CHD; 2 - Laserdisc (LD); 3 - CD; 4 - DVD; 5 - LD/CD/DVD image file;
    eIconLoaded: Boolean;
    eDescription: String;
    eYear: String[4];
    eManufacturer: String;

    eAudioChannels: ShortInt;
    eAudioSamples: ShortInt;
    eAudioSampleName: String;

    eControlType: ShortInt;
    eControls: String;
    eNumberScreens: ShortInt;

    eScreenType1: ShortInt;
    eScreenRotation1: SmallInt;
    eResolutionWidth1: SmallInt;
    eResolutionHeight1: SmallInt;
    eRefreshRate1: String;

    eScreenType2: ShortInt;
    eScreenRotation2: SmallInt;
    eResolutionWidth2: SmallInt;
    eResolutionHeight2: SmallInt;
    eRefreshRate2: String;

    eScreenType3: ShortInt;
    eScreenRotation3: SmallInt;
    eResolutionWidth3: SmallInt;
    eResolutionHeight3: SmallInt;
    eRefreshRate3: String;

    eScreenType4: ShortInt;
    eScreenRotation4: SmallInt;
    eResolutionWidth4: SmallInt;
    eResolutionHeight4: SmallInt;
    eRefreshRate4: String;

    eDriverStatus: ShortInt;
    eEmulationStatus: ShortInt;
    eColorStatus: ShortInt;
    eSoundStatus: ShortInt;
    eGraphicStatus: ShortInt;
    eCocktailStatus: ShortInt;
    eProtectionStatus: ShortInt;

    eCategory: String;
    eVersionAdded: String[20];

    eName: String;
    eClone: String;
    eDriverName: String;
    eBiosName: String;

    eMerged: String[20];

    ePlayTimeInteger: Int64;
    ePlayTime: String;

    ePlayed: Integer;
    eNumberPlayers: String;

    eGameSize: String[12]; // also can be used to store number of LD/CD/DVD discs
    eSaveState: ShortInt;
    eChipCPU: String;
  end;
  pGameInfo = ^TGameInfo;

type
  TGameSortCompare = function (Item1, Item2: pGameInfo; ColumnID: Integer): Integer;

type
  TSongType = packed record
    Module: PFMusicModule;
    Stream: PFSoundStream;
    Channel: Integer;
    Playing: Boolean;
  end;

type
  TImageDetailsRecord = record
    FileName: String;
    ZipFileName: String;
    Size: Integer;
    ResolutionX: Integer;
    ResolutionY: Integer;
    AspectRatioResolutionX: Integer;
    AspectRatioResolutionY: Integer;
  end;

const
  MaxGameID = 29; // latest ROM ID used by the last system
  MissingIconFileMsg: String = 'File "%s" is missing. Frontend icons '+
                               'will not be displayed in the correct indexes!'; // LoadIcon routines

type
  TFormMain = class(TForm)
    MainMenu: TBcBarMainMenu;
    MenuFile: TMenuItem;
    MenuCreateGamesList: TMenuItem;
    MenuPreferences: TMenuItem;
    MenuExit: TMenuItem;
    MenuEmulatorSetup: TMenuItem;
    N3: TMenuItem;
    MenuHelp: TMenuItem;
    MenuAbout: TMenuItem;
    PopupMenuImages: TBcBarPopupMenu;
    N5: TMenuItem;
    PopupDeleteCurrentImage: TMenuItem;
    PopupRenameCurrentImage: TMenuItem;
    PopupMenuGamesList: TBcBarPopupMenu;
    PopupPlayGameStandard: TMenuItem;
    PopupPlayCustom_ZiNc: TMenuItem;
    PopupSetCustomOptions: TMenuItem;
    PopupDeleteCustomOptions: TMenuItem;
    PopupAuditSelectedGame: TMenuItem;
    PopupAuditAllGamesMAME: TMenuItem;
    N10: TMenuItem;
    PopupAddToFavorites: TMenuItem;
    PopupDeleteFromFavorites: TMenuItem;
    N14: TMenuItem;
    PopupRefreshAllGamesMAME: TMenuItem;
    PopupRefreshSelectedGame: TMenuItem;
    N15: TMenuItem;
    N17: TMenuItem;
    MenuPlayRecordedGame: TMenuItem;
    MenuRecordGame: TMenuItem;
    MenuFavoriteProfileEditor: TMenuItem;
    MenuView: TMenuItem;
    MenuImages: TMenuItem;
    GamesListSaveDialog: TSaveDialog;
    N34: TMenuItem;
    MenuVisitEmuLoaderHomepage: TMenuItem;
    SendEMailEmuLoader: TMenuItem;
    N35: TMenuItem;
    MenuAdvancedUser: TMenuItem;
    PopupShowFirstImage: TMenuItem;
    PopupAuditAvailableGamesMAME: TMenuItem;
    PopupRefreshAvailableGamesMAME: TMenuItem;
    PopupRefreshMissingGamesMAME: TMenuItem;
    MenuRestoreMainScreenDefaultScreenSizePosition: TMenuItem;
    N44: TMenuItem;
    PopupCustomGameOptions: TMenuItem;
    PopupAuditGames: TMenuItem;
    PopupRefreshGames: TMenuItem;
    MenuMAMEDefaultSettings: TMenuItem;
    MenuColumnsEditor: TMenuItem;
    PopupSetGameDriverCustomOptions: TMenuItem;
    PopupDeleteGameDriverCustomOptions: TMenuItem;
    PopupSetDebugCustomOptions: TMenuItem;
    PopupDeleteDebugCustomOptions: TMenuItem;
    PopupDeleteZIPFileName: TMenuItem;
    PopupIcons: TMenuItem;
    MenuParentalLock: TMenuItem;
    PopupGamesUseMAMu_Icons: TMenuItem;
    N84: TMenuItem;
    PopupShowParentIconOnly: TMenuItem;
    MenuParentalLockEditor: TMenuItem;
    MenuShowActiveMAMEROMPaths: TMenuItem;
    N90: TMenuItem;
    ToolBarButtons: TToolBar;
    PanelGameImages: TPanel;
    PanelList: TPanel;
    Splitter: TSplitter;
    MenuEmulatorDefaultSettings: TMenuItem;
    MenuShowImages: TMenuItem;
    N96: TMenuItem;
    MenuVisitSlikStikHomepage: TMenuItem;
    MenuVisitXArcadeHomepage: TMenuItem;
    MenuVisitHotRodHomepage: TMenuItem;
    FontDialog: TFontDialog;
    ToolBarPanel: TCoolBar;
    PopupExitApplication: TMenuItem;
    ButtonImagesViewMode: TToolButton;
    PopupMenuImageTypes: TBcBarPopupMenu;
    ButtonShowTitleSnapshots: TMenuItem;
    ButtonShowGameSnapshots: TMenuItem;
    ButtonShowMarquees: TMenuItem;
    ButtonShowFlyers: TMenuItem;
    ButtonShowCabinets: TMenuItem;
    ButtonShowControlPanels: TMenuItem;
    ButtonShowControlPanelLayouts: TMenuItem;
    PopupGameFilterHaveMiss: TBcBarPopupMenu;
    PopupShowHaveMiss: TMenuItem;
    PopupShowHave: TMenuItem;
    PopupShowMiss: TMenuItem;
    ButtonGameFilterHaveMiss: TToolButton;
    OpenDialog: TOpenDialog;
    MenuExportGamesListTextFile: TMenuItem;
    N2: TMenuItem;
    MenuEmulator: TMenuItem;
    PopupAddGameParentalLock: TMenuItem;
    Separator_FullScreen: TMenuItem;
    PopupCheckMissingIcons: TMenuItem;
    PopupCheckNotUsedIcons: TMenuItem;
    ZipForge: TZipForge;
    TimerFMOD: TTimer;
    MenuUserManual: TMenuItem;
    N32: TMenuItem;
    PopupSelectParentGame: TMenuItem;
    PopupDeleteAudioFileName: TMenuItem;
    PopupCustomSettings: TMenuItem;
    PopupFavoriteGames: TMenuItem;
    PopupDeleteSelected: TMenuItem;
    N36: TMenuItem;
    PopupDeleteCFGFile: TMenuItem;
    PopupDeleteNVRAMFile: TMenuItem;
    PopupDeleteINPFile: TMenuItem;
    PopupDeleteStateFile: TMenuItem;
    MenuVisitDevastator2Homepage: TMenuItem;
    MenuImageResampler: TMenuItem;
    MenuImageFilterLinear: TMenuItem;
    MenuImageFilterLanczos: TMenuItem;
    MenuImageFilterMitchell: TMenuItem;
    MenuImageFilterSpline: TMenuItem;
    N41: TMenuItem;
    MenuImageFilterOff: TMenuItem;
    MenuViewEmulatorFullCommandLine: TMenuItem;
    ButtonViewMode: TToolButton;
    PopupMenuViewMode: TBcBarPopupMenu;
    ButtonViewModeSystem: TMenuItem;
    ButtonViewModeGroupedSystem: TMenuItem;
    ButtonViewModeStandard: TMenuItem;
    ButtonViewModeGrouped: TMenuItem;
    ButtonGameFilterHideBios: TToolButton;
    PopupGameFilterMasterClone: TBcBarPopupMenu;
    PopupShowMasterClone: TMenuItem;
    PopupShowMaster: TMenuItem;
    PopupShowClone: TMenuItem;
    PopupGameFilterWorkingNonWorking: TBcBarPopupMenu;
    PopupShowWorkingNonWorking: TMenuItem;
    PopupShowWorking: TMenuItem;
    PopupShowNonWorking: TMenuItem;
    ButtonGameFilterWorkingNonWorking: TToolButton;
    PopupIconSizeLarge: TMenuItem;
    MasterFont: TFontDialog;
    CloneFont: TFontDialog;
    PreliminaryFont: TFontDialog;
    MenuImageFilterCousine: TMenuItem;
    ButtonGroupedBlendCloneIcons50Percent: TMenuItem;
    ButtonGroupedToggleExpandedClosed: TMenuItem;
    PopupAuditDownloadAddress: TMenuItem;
    MenuRandomGamePreview: TMenuItem;
    OpenImageDialog: TOpenPictureDialog;
    PanelScreenshotsArea: TPanel;
    N9: TMenuItem;
    ButtonShowMAWSGameInfo: TMenuItem;
    MenuVisitHomepage: TMenuItem;
    N18: TMenuItem;
    MenuVisitMAWSHomepage: TMenuItem;
    MenuVisitMAMEHomepage: TMenuItem;
    MenuVisitCatlistHomepage: TMenuItem;
    MenuVisitMAMu_Homepage: TMenuItem;
    PopupAuditNotUsedFiles: TMenuItem;
    MenuMAMEInput: TMenuItem;
    N4: TMenuItem;
    N6: TMenuItem;
    PopupGameDocuments: TMenuItem;
    PopupGameInformation: TMenuItem;
    PopupAutomaticGameInformation: TMenuItem;
    PopupGameHistory: TMenuItem;
    PopupGameDriverInformation: TMenuItem;
    PopupGameFAQ: TMenuItem;
    MenuVisitMashMameInfo: TMenuItem;
    MenuVisitEasyEmu: TMenuItem;
    MenuCreateZiNcGamesList: TMenuItem;
    MenuCreateDaphneGamesList: TMenuItem;
    MenuZiNcDefaultSettings: TMenuItem;
    MenuDaphneDefaultSettings: TMenuItem;
    MenuCreateMAMEGamesList: TMenuItem;
    ButtonGameFilterMasterClone: TToolButton;
    N12: TMenuItem;
    ButtonShowSelect: TMenuItem;
    ButtonShowVersus: TMenuItem;
    ButtonShowWallpapers: TMenuItem;
    ButtonShowHardware: TMenuItem;
    ButtonShowCustomImage: TMenuItem;
    ButtonGameFilterMain: TToolButton;
    N13: TMenuItem;
    ShowActiveZiNcROMPaths1: TMenuItem;
    PopupRefreshAllGamesZiNc: TMenuItem;
    PopupRefreshAllGamesDaphne: TMenuItem;
    MenuDaphneRunFullScreen: TMenuItem;
    MenuRecordMAMEAudio: TMenuItem;
    N22: TMenuItem;
    MenuToolBarSettings: TMenuItem;
    IL_ToolBarButtons: TImageList;
    IL_MenuPopup: TImageList;
    IL_StandardIconsLarge: TImageList;
    IL_StandardIconsStandard: TImageList;
    IL_StandardIconsSmall: TImageList;
    IL_StatusBar: TImageList;
    IL_ArcadeSystem_Large: TImageList;
    IL_ArcadeSystem_Small: TImageList;
    IL_ImagesViewMode_Small: TImageList;
    IL_FilterWorkingNonWorking_Small: TImageList;
    IL_FilterWorkingNonWorking_Large: TImageList;
    IL_FilterHaveMiss_Small: TImageList;
    IL_FilterHaveMiss_Large: TImageList;
    IL_FilterMasterClone_Small: TImageList;
    IL_FilterMasterClone_Large: TImageList;
    IL_ViewMode_Small: TImageList;
    IL_ViewMode_Large: TImageList;
    IL_Columns: TImageList;
    MenuController: TMenuItem;
    MenuImagesToolBarEditor: TMenuItem;
    MenuCreateAGEMAMEGamesList: TMenuItem;
    PopupRefreshAllGamesAGEMAME: TMenuItem;
    MenuShowActiveAGEMAMEROMPaths: TMenuItem;
    ZipForgeMAMu_: TZipForge;
    PopupReloadMAMu_Icons: TMenuItem;
    NotebookImages: TNotebook;
    PanelImagesDocuments: TPanel;
    SplitterMAMEInfo: TSplitter;
    PanelImage: TPanel;
    ImagesToolBarPanel: TCoolBar;
    ImagesToolbarButtons: TToolBar;
    ButtonPreviousImage: TToolButton;
    ButtonNextImage: TToolButton;
    ButtonPreviousType: TToolButton;
    ButtonNextType: TToolButton;
    ButtonImageToolBarViewMode: TToolButton;
    LabelImageNumber: TPanel;
    Images: TImage32;
    PanelWebBrowser: TPanel;
    WebBrowser: TWebBrowser;
    WebToolbarBarPanel: TCoolBar;
    WebToolBarButtons: TToolBar;
    WebButtonStop: TToolButton;
    WebButtonRefresh: TToolButton;
    WebStatusBarPanel: TPanel;
    WebStatusBar: TStatusBar;
    WebProgressBar: TProgressBar;
    ButtonGameFilterArcade: TToolButton;
    PopupGameArcadeFilters: TBcBarPopupMenu;
    PopupArcadeMAME: TMenuItem;
    PopupArcadeZiNc: TMenuItem;
    PopupArcadeDaphne: TMenuItem;
    PopupArcadeAGEMAME: TMenuItem;
    PopupArcadeListAll: TMenuItem;
    IL_ArcadeFilter_Small: TImageList;
    IL_ArcadeFilter_Large: TImageList;
    N16: TMenuItem;
    WebButtonExit: TToolButton;
    ButtonImageVisualEffects: TToolButton;
    PopupImageVisualEffects: TBcBarPopupMenu;
    PopupImageStretch: TMenuItem;
    PopupImageStretchLarger: TMenuItem;
    PopupImageScreenAspectRatio: TMenuItem;
    N21: TMenuItem;
    PopupImageFlipHorizontal: TMenuItem;
    PopupImageFlipVertical: TMenuItem;
    PopupImageRotate90: TMenuItem;
    PopupImageDisplayParent: TMenuItem;
    MenuCreatePinMAMEGamesList: TMenuItem;
    MenuShowActivePinMAMEROMPaths: TMenuItem;
    PopupArcadePinMAME: TMenuItem;
    PopupRefreshAllGamesPinMAME: TMenuItem;
    MenuGenerateZiNcDriverFile: TMenuItem;
    MenuViewEmulatorsVersions: TMenuItem;
    N11: TMenuItem;
    MenuExportAllFilesFullFormat: TMenuItem;
    MenuExportAllGamesGameNameOnly: TMenuItem;
    MenuExportVisibleGamesFullFormat: TMenuItem;
    MenuExportVisibleGamesGameNameOnly: TMenuItem;
    PopupAuditMAME: TMenuItem;
    PopupAuditAGEMAME: TMenuItem;
    PopupAuditAvailableGamesAGEMAME: TMenuItem;
    PopupAuditAllGamesAGEMAME: TMenuItem;
    PopupAuditPinMAME: TMenuItem;
    PopupAuditAvailableGamesPinMAME: TMenuItem;
    PopupAuditAllGamesPinMAME: TMenuItem;
    MenuImageSettings: TMenuItem;
    MenuMAMELoadSaveState: TMenuItem;
    MenuBiosSetsMAME: TMenuItem;
    MenuBiosSetDefaultDisabled: TMenuItem;
    MenuBiosSetUserDefined: TMenuItem;
    MenuBiosSetSettings: TMenuItem;
    MenuAdvancedUserMAME: TMenuItem;
    PopupGameDocsShowAll: TMenuItem;
    N24: TMenuItem;
    PopupDeleteVideoFileName: TMenuItem;
    MenuRecordMAMEVideo: TMenuItem;
    N25: TMenuItem;
    N26: TMenuItem;
    MenuSetFoldersAudioMNG: TMenuItem;
    MenuArcadeControllersLayout: TMenuItem;
    ArcadeLayoutDevastator2: TMenuItem;
    ArcadeLayoutXArcade: TMenuItem;
    ArcadeLayoutSlikStik: TMenuItem;
    ArcadeLayoutHotRodSE: TMenuItem;
    MenuSmallToolBar: TMenuItem;
    Draft1: TMenuItem;
    Box1: TMenuItem;
    Cubic1: TMenuItem;
    MenuImagesScanNotUsedImages: TMenuItem;
    MenuImagesScanForMissingImages: TMenuItem;
    N20: TMenuItem;
    MenuViewGamesListVersions: TMenuItem;
    PopupRefreshGamesMAME: TMenuItem;
    PopupRefreshGamesZiNc: TMenuItem;
    PopupRefreshGamesDaphne: TMenuItem;
    PopupRefreshGamesAGEMAME: TMenuItem;
    PopupRefreshGamesPinMAME: TMenuItem;
    PopupRefreshAvailableGamesZiNc: TMenuItem;
    PopupRefreshAvailableGamesDaphne: TMenuItem;
    PopupRefreshAvailableGamesAGEMAME: TMenuItem;
    PopupRefreshAvailableGamesPinMAME: TMenuItem;
    PopupRefreshMissingGamesZiNc: TMenuItem;
    PopupRefreshMissingGamesDaphne: TMenuItem;
    PopupRefreshMissingGamesAGEMAME: TMenuItem;
    PopupRefreshMissingGamesPinMAME: TMenuItem;
    BcDrawModule: TBcCustomDrawModule;
    MenuMAMEDefaultInputFile: TMenuItem;
    MenuMAMESelectInputFile: TMenuItem;
    MenuAGEMAMEDefaultSettings: TMenuItem;
    MenuPinMAMEDefaultSettings: TMenuItem;
    GamesTreeView: TVirtualStringTree;
    PopupGameFilterNumberScreens: TBcBarPopupMenu;
    PopupShowSreensAll: TMenuItem;
    PopupShowSreens1: TMenuItem;
    PopupShowSreens2: TMenuItem;
    PopupShowSreens3: TMenuItem;
    PopupShowSreens4: TMenuItem;
    IL_FilterNumberScreens_Small: TImageList;
    IL_FilterNumberScreens_Large: TImageList;
    ButtonGameFilterNumberScreens: TToolButton;
    detectvideo1: TMenuItem;
    PopupIconSizeStandard: TMenuItem;
    PopupIconSizeSmall: TMenuItem;
    N1: TMenuItem;
    MenuSmallStatusBar: TMenuItem;
    PopupGameIconSize: TMenuItem;
    MenuLargeStatusBar: TMenuItem;
    MenuStandardStatusBar: TMenuItem;
    MenuStatusBarSize: TMenuItem;
    MenuROMsPaths: TMenuItem;
    MenuViewGameDetails: TMenuItem;
    MenuViewFullScreen: TMenuItem;
    PopupReturnToWindowMode: TMenuItem;
    PopupImageViewInFullScreen: TMenuItem;
    PopupImageInfo: TMenuItem;
    PopupCustomCommandLine: TMenuItem;
    PopupPlayCustom: TMenuItem;
    PopupPlayCustom_CommandLine: TMenuItem;
    PopupSetGameCustomCommandLine: TMenuItem;
    PopupDeleteGameCustomCommandLine: TMenuItem;
    N7: TMenuItem;
    PopupSetDriverCustomCommandLine: TMenuItem;
    PopupDeleteDriverCustomCommandLine: TMenuItem;
    N8: TMenuItem;
    N19: TMenuItem;
    N23: TMenuItem;
    PopupSetSystemCustomCommandLine: TMenuItem;
    PopupDeleteSystemCustomCommandLine: TMenuItem;
    CustomGamesEditor1: TMenuItem;
    MenuViewForceQuotesCommandLine: TMenuItem;
    MenuShowActiveHazeMDROMPaths: TMenuItem;
    MenuViewCPUFilterBox: TMenuItem;
    ToolBarCPUFilter: TCoolBar;
    PanelIncrementalSearch: TPanel;
    LabelFilterCPU: TLabel;
    ButtonFilterCPUApply: TButton;
    FilterCPU: TEdit;
    MenuCreateHazeMDGamesList: TMenuItem;
    PopupArcadeHazeMD: TMenuItem;
    PopupRefreshGamesHazeMD: TMenuItem;
    PopupScanAvailableGamesHazeMD: TMenuItem;
    PopupScanMissingGamesHazeMD: TMenuItem;
    PopupScanAllGamesHazeMD: TMenuItem;
    HazeMD1: TMenuItem;
    PopupAuditAvailableGamesHazeMD: TMenuItem;
    PopupAuditAllGamesHazeMD: TMenuItem;
    MenuHazeMDDefaultSettings: TMenuItem;
    FilterCPUList: TComboBox;
    StatusBarPanel: TCoolBar;
    ToolBarStatusBar: TToolBar;
    StatusBar_TotalEntries: TToolButton;
    StatusBar_GameSize: TToolButton;
    StatusBar_GameName: TToolButton;
    ButtonRandomGame: TToolButton;
    StatusBar_FavoritesProfile: TToolButton;
    MenuViewStatusBar: TMenuItem;
    MenuStatusBarSettings: TMenuItem;
    MenuViewToolBar: TMenuItem;
    MenuViewGamesList: TMenuItem;
    MenuGameSizeFormat: TMenuItem;
    MenuGameSizeBits: TMenuItem;
    MenuGameSizeBytes: TMenuItem;
    MenuGameSizeZipFileBytes: TMenuItem;
    MenuViewFilesVersions: TMenuItem;
    MenuCreateAllSystemsGamesList: TMenuItem;
    MenuImagesConverttoOldFormat: TMenuItem;
    N27: TMenuItem;
    N28: TMenuItem;
    MenuImagesNewFormat: TMenuItem;
    MenuImagesELFormat: TMenuItem;
    MenuImagesOldFormat: TMenuItem;
    PopupGameDocsFeatureNotAvailable: TMenuItem;
    PopupDeleteZipFileNamesFavoritesProfile: TMenuItem;
    PopupDeleteMultipleZipFileNames: TMenuItem;
    N29: TMenuItem;
    MenuGames: TMenuItem;
    MenuGamesEnableMultipleSelection: TMenuItem;
    MenuIncrementalSearch: TMenuItem;
    MenuIncrementalSearchDescription: TMenuItem;
    MenuIncrementalSearchGameName: TMenuItem;
    MenuGamesFillAllCloneEntries: TMenuItem;
    PopupGameStory: TMenuItem;
    CoolTrayIcon: TCoolTrayIcon;
    IL_TrayIcon: TImageList;
    MenuReloadFrontendIcons: TMenuItem;
    N30: TMenuItem;
    ReloadGamesListIcons1: TMenuItem;
    PanelGameDocuments: TPanel;
    MAMEInfoTextHolder: TRichEdit;
    GameDocumentsToolBarPanel: TCoolBar;
    GameDocumentsToolBarButtons: TToolBar;
    GameDocumentsLayout1_Top: TToolButton;
    GameDocumentsLayout2_Bottom: TToolButton;
    GameDocumentsLayout3_Left: TToolButton;
    GameDocumentsLayout4_Right: TToolButton;
    GameDocumentsFont: TToolButton;
    PopupGameDocsEnableToolBar: TMenuItem;
    procedure MenuExitClick(Sender: TObject);
    procedure MenuPreferencesClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure MenuEmulatorSetupClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure MenuAboutClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure MenuImagesClick(Sender: TObject);
    procedure SendEMailEmuLoaderClick(Sender: TObject);
    procedure MenuVisitEmuLoaderHomepageClick(Sender: TObject);
    procedure MenuRestoreMainScreenDefaultScreenSizePositionClick(
      Sender: TObject);
    procedure MenuAdvancedUserClick(Sender: TObject);
    procedure MenuMAMEDefaultSettingsClick(Sender: TObject);
    procedure MenuColumnsEditorClick(Sender: TObject);
    procedure MenuParentalLockClick(Sender: TObject);
    procedure MenuPlayRecordedGameClick(Sender: TObject);
    procedure MenuRecordGameClick(Sender: TObject);
    procedure MenuFavoriteProfileEditorClick(Sender: TObject);
    procedure MenuParentalLockEditorClick(
      Sender: TObject);
    procedure PopupGamesUseMAMu_IconsClick(Sender: TObject);
    procedure MenuShowActiveMAMEROMPathsClick(Sender: TObject);
    procedure MenuShowImagesClick(Sender: TObject);
    procedure PopupShowHaveMissClick(Sender: TObject);
    procedure ZipForgeProcessFileFailure(Sender: TObject; FileName: String;
      Operation: TZFProcessOperation; NativeError, ErrorCode: Integer;
      ErrorMessage: String; var Action: TZFAction);
    procedure TimerFMODTimer(Sender: TObject);
    procedure MenuUserManualClick(Sender: TObject);
    procedure MenuImageFilterOffClick(Sender: TObject);
    procedure PopupRefreshAvailableGamesMAMEClick(Sender: TObject);
    procedure ButtonGameFilterHideBiosClick(Sender: TObject);
    procedure PopupShowMasterCloneClick(Sender: TObject);
    procedure PopupShowWorkingNonWorkingClick(Sender: TObject);
    procedure PopupShowParentIconOnlyClick(Sender: TObject);
    procedure GamesTreeViewGetText(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
      var CellText: WideString);
    procedure GamesTreeViewGetImageIndex(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
      var Ghosted: Boolean; var ImageIndex: Integer);
    procedure GamesTreeViewHeaderClick(Sender: TVTHeader;
      Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
      Y: Integer);
    procedure GamesTreeViewCompareNodes(Sender: TBaseVirtualTree; Node1,
      Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
    procedure GamesTreeViewFreeNode(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure GamesTreeViewChange(Sender: TBaseVirtualTree;
      Node: PVirtualNode);
    procedure ButtonGroupedBlendCloneIcons50PercentClick(Sender: TObject);
    procedure GamesTreeViewPaintText(Sender: TBaseVirtualTree;
      const TargetCanvas: TCanvas; Node: PVirtualNode;
      Column: TColumnIndex; TextType: TVSTTextType);
    procedure GamesTreeViewIncrementalSearch(Sender: TBaseVirtualTree;
      Node: PVirtualNode; const SearchText: WideString;
      var Result: Integer);
    procedure ButtonGroupedToggleExpandedClosedClick(Sender: TObject);
    procedure PopupMenuGamesListPopup(Sender: TObject);
    procedure MenuRandomGamePreviewClick(Sender: TObject);
    procedure WebButtonStopClick(Sender: TObject);
    procedure WebButtonRefreshClick(Sender: TObject);
    procedure WebBrowserProgressChange(Sender: TObject; Progress,
      ProgressMax: Integer);
    procedure ZipForgeOverallProgress(Sender: TObject; Progress: Double;
      Operation: TZFProcessOperation; ProgressPhase: TZFProgressPhase;
      var Cancel: Boolean);
    procedure WebBrowserStatusTextChange(Sender: TObject;
      const Text: WideString);
    procedure ButtonShowMAWSGameInfoClick(Sender: TObject);
    procedure ButtonShowGameSnapshotsClick(Sender: TObject);
    procedure PopupShowFirstImageClick(Sender: TObject);
    procedure PopupRenameCurrentImageClick(Sender: TObject);
    procedure PopupDeleteCurrentImageClick(Sender: TObject);
    procedure PopupDeleteZIPFileNameClick(Sender: TObject);
    procedure PopupDeleteAudioFileNameClick(Sender: TObject);
    procedure PopupDeleteCFGFileClick(Sender: TObject);
    procedure PopupCheckMissingIconsClick(Sender: TObject);
    procedure PopupCheckNotUsedIconsClick(Sender: TObject);
    procedure PopupAddToFavoritesClick(Sender: TObject);
    procedure PopupDeleteFromFavoritesClick(Sender: TObject);
    procedure PopupAddGameParentalLockClick(Sender: TObject);
    procedure PopupPlayGameStandardClick(Sender: TObject);
    procedure PopupSetCustomOptionsClick(Sender: TObject);
    procedure PopupDeleteCustomOptionsClick(Sender: TObject);
    procedure PopupSetGameDriverCustomOptionsClick(Sender: TObject);
    procedure PopupDeleteGameDriverCustomOptionsClick(Sender: TObject);
    procedure PopupSetDebugCustomOptionsClick(Sender: TObject);
    procedure PopupDeleteDebugCustomOptionsClick(Sender: TObject);
    procedure PopupSelectParentGameClick(Sender: TObject);
    procedure PopupRefreshSelectedGameClick(Sender: TObject);
    procedure PopupAuditSelectedGameClick(Sender: TObject);
    procedure PopupAuditDownloadAddressClick(Sender: TObject);
    procedure PopupGameDocumentsClick(Sender: TObject);
    procedure PopupGameInformationClick(Sender: TObject);
    procedure PopupGameHistoryClick(Sender: TObject);
    procedure PopupGameDriverInformationClick(Sender: TObject);
    procedure PopupGameFAQClick(Sender: TObject);
    procedure PopupAutomaticGameInformationClick(Sender: TObject);
    procedure MenuCreateMAMEGamesListClick(Sender: TObject);
    procedure MenuCreateZiNcGamesListClick(Sender: TObject);
    procedure GamesTreeViewGetHint(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: TColumnIndex;
      var LineBreakStyle: TVTTooltipLineBreakStyle;
      var HintText: WideString);
    procedure GamesTreeViewKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure GamesTreeViewKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure MenuCreateDaphneGamesListClick(Sender: TObject);
    procedure ButtonPreviousImageClick(Sender: TObject);
    procedure ButtonNextImageClick(Sender: TObject);
    procedure ButtonNextTypeClick(Sender: TObject);
    procedure ButtonPreviousTypeClick(Sender: TObject);
    procedure ImagesClick(Sender: TObject);
    procedure MenuToolBarSettingsClick(Sender: TObject);
    procedure MenuImagesToolBarEditorClick(Sender: TObject);
    procedure ToolBarButtonsMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure ImagesToolbarButtonsMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure PopupArcadeListAllClick(Sender: TObject);
    procedure WebButtonExitClick(Sender: TObject);
    procedure PopupImageFlipHorizontalClick(Sender: TObject);
    procedure PopupImageStretchClick(Sender: TObject);
    procedure WebBrowserEnter(Sender: TObject);
    procedure MenuGenerateZiNcDriverFileClick(Sender: TObject);
    procedure MenuViewEmulatorsVersionsClick(Sender: TObject);
    procedure MenuExportAllFilesFullFormatClick(Sender: TObject);
    procedure PopupAuditAllGamesMAMEClick(Sender: TObject);
    procedure PopupAuditAllGamesAGEMAMEClick(Sender: TObject);
    procedure PopupAuditAllGamesPinMAMEClick(Sender: TObject);
    procedure MenuImageSettingsClick(Sender: TObject);
    procedure MenuMAMELoadSaveStateClick(Sender: TObject);
    procedure MenuBiosSetSettingsClick(Sender: TObject);
    procedure PopupDeleteVideoFileNameClick(Sender: TObject);
    procedure MenuSetFoldersAudioMNGClick(Sender: TObject);
    procedure ArcadeLayoutDevastator2Click(Sender: TObject);
    procedure ButtonGameFilterMainClick(Sender: TObject);
    procedure MenuSmallToolBarClick(Sender: TObject);
    procedure MenuImagesScanNotUsedImagesClick(Sender: TObject);
    procedure MenuImagesScanForMissingImagesClick(Sender: TObject);
    procedure PopupGameDocsShowAllClick(Sender: TObject);
    procedure MenuViewGamesListVersionsClick(Sender: TObject);
    procedure PopupRefreshAvailableGamesZiNcClick(Sender: TObject);
    procedure PopupRefreshAvailableGamesDaphneClick(Sender: TObject);
    procedure PopupRefreshAvailableGamesAGEMAMEClick(Sender: TObject);
    procedure PopupRefreshAvailableGamesPinMAMEClick(Sender: TObject);
    procedure BcDrawModuleDrawMenuItem(Sender: TObject;
      AMenuItem: TMenuItem; ACanvas: TCanvas; ARect: TRect;
      State: TOwnerDrawState; ABarVisible: Boolean;
      var DefaultDraw: Boolean);
    procedure BcDrawModuleMeasureMenuItem(Sender: TObject;
      AMenuItem: TMenuItem; ACanvas: TCanvas; var Width, Height: Integer;
      ABarVisible: Boolean; var DefaultMeasure: Boolean);
    procedure MainMenuMeasureMenuItem(Sender: TObject;
      AMenuItem: TMenuItem; ACanvas: TCanvas; var Width, Height: Integer;
      ABarVisible: Boolean; var DefaultMeasure: Boolean);
    procedure MenuMAMESelectInputFileClick(Sender: TObject);
    procedure ButtonViewModeStandardClick(Sender: TObject);
    procedure PopupShowSreensAllClick(Sender: TObject);
    procedure detectvideo1Click(Sender: TObject);
    procedure PopupIconSizeStandardClick(Sender: TObject);
    procedure MenuStandardStatusBarClick(Sender: TObject);
    procedure MenuViewGameDetailsClick(Sender: TObject);
    procedure MenuViewFullScreenClick(Sender: TObject);
    procedure PopupReturnToWindowModeClick(Sender: TObject);
    procedure PopupImageInfoClick(Sender: TObject);
    procedure PopupSetGameCustomCommandLineClick(Sender: TObject);
    procedure PopupDeleteGameCustomCommandLineClick(Sender: TObject);
    procedure PopupCustomSettingsClick(Sender: TObject);
    procedure CustomGamesEditor1Click(Sender: TObject);
    procedure MenuViewForceQuotesCommandLineClick(Sender: TObject);
    procedure MenuViewCPUFilterBoxClick(Sender: TObject);
    procedure ButtonFilterCPUApplyClick(Sender: TObject);
    procedure FilterCPUKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure PopupScanAvailableGamesHazeMDClick(Sender: TObject);
    procedure PopupAuditAllGamesHazeMDClick(Sender: TObject);
    procedure ButtonRandomGameClick(Sender: TObject);
    procedure StatusBar_GameSizeClick(Sender: TObject);
    procedure StatusBar_FavoritesProfileClick(Sender: TObject);
    procedure MenuGameSizeBitsClick(Sender: TObject);
    procedure MenuStatusBarSettingsClick(Sender: TObject);
    procedure ToolBarStatusBarMouseDown(Sender: TObject;
      Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    procedure MenuImagesConverttoOldFormatClick(Sender: TObject);
    procedure PopupGameDocsFeatureNotAvailableClick(Sender: TObject);
    procedure PopupDeleteMultipleZipFileNamesClick(Sender: TObject);
    procedure MenuGamesEnableMultipleSelectionClick(Sender: TObject);
    procedure MenuIncrementalSearchDescriptionClick(Sender: TObject);
    procedure PopupIconsClick(Sender: TObject);
    procedure PopupRefreshGamesClick(Sender: TObject);
    procedure PopupAuditGamesClick(Sender: TObject);
    procedure PopupFavoriteGamesClick(Sender: TObject);
    procedure PopupGameStoryClick(Sender: TObject);
    procedure MenuReloadFrontendIconsClick(Sender: TObject);
    procedure ReloadGamesListIcons1Click(Sender: TObject);
    procedure PopupGameDocsEnableToolBarClick(Sender: TObject);
    procedure GameDocumentsLayout1_TopClick(Sender: TObject);
    procedure SplitterMAMEInfoCanResize(Sender: TObject;
      var NewSize: Integer; var Accept: Boolean);
    procedure GameDocumentsLayout2_BottomClick(Sender: TObject);
    procedure GameDocumentsLayout3_LeftClick(Sender: TObject);
    procedure GameDocumentsLayout4_RightClick(Sender: TObject);
    procedure GameDocumentsFontClick(Sender: TObject);

  private
    FileIcon: TIcon;
    Use32bitsIcons, TerminateEmuLoader: Boolean;

    AddParentSet: Boolean;
    FullList: THashedStringList; // temp file for games list
    ListGames, ListROMs: TMemIniFile;

    ProcessingAutomaticMAMEInfoDAT, EmulatorRunOnce: Boolean;

    //temporary variable to workarround the closing window after activating parental lock
    CloseStatusWindow: Boolean;

    FormMainWidth, FormMainHeight, FormMainTop, FormMainLeft: SmallInt;
    ImageZIP: String;
    samplesDir: packed array[1..MaxArcadeSystems] of String;
    ImageNumber: ShortInt;
    ImageDetails: packed array[1..4] of TImageDetailsRecord;
    imgZipContents, imgZipContentsFullPath: packed array[1..MaxArcadeSystems] of THashedStringList;
    MAMu_ZipContents: THashedStringList;
    icoStream: TMemoryStream;

    // FMOD
    FSongs: packed array [0..1] of TSongType;

    FDrawBuffer: TBitmap;
    function GetDrawBuffer: TBitmap;

    procedure LoadSound(romID: Integer; MasterName, CloneName: String);
    procedure PlaySound;
    procedure StopSound;
    // FMOD

    // get column text / hint for TVirtualStringTree
    function GetColumnText(DataHolder: pGameInfo; idxColumn: Integer): String;

    procedure MinimizeToTray;
    procedure RestoreFromTray;

    procedure ResetMAMu_ImageList;

    // Treeview procedures
    procedure SortColumn(ForceAscending: Boolean);
    procedure FocusGamesList;
    procedure RunMAMEInitialize(SystemID: ShortInt);
    procedure RunCreateGamesSys(const SystemID: Integer); // for zinc and daphne
    procedure SetColumnsProfileFirstRun;
    function  VerifyTempDirectory: Boolean;
    procedure InitializeColumnsSort;
    procedure InitializeEmulatorVariables;

    // Load Icons in TImageList components
    procedure ClearImageList(IL_Holder: TImageList);
    function  LoadTrayIcons: Boolean;
    function  LoadMainScreenIcons(Reload: Boolean = False): Boolean;
    function  LoadStatusBarIcons: Boolean;
    function  LoadMAMESettingsIcons(IconList: TImageList): Boolean;
    function  LoadAuditIcons: Boolean;
    function  LoadParentalLockIcons: Boolean;
    function  LoadCustomizeColumnsIcons: Boolean;
    function  LoadMAMu_SettingsIcons(ImageListHolder: TImageList): Boolean;

    procedure SetImageMode(TypeIndex: ShortInt);
    procedure FreeMemoryZipContents(SystemID: Integer = -1);

    function  LoadGames(SystemID: Integer; IsFavorite: Boolean; FavFile: String = ''): Boolean;

    //function  LoadParentalLockPassword: String;

    // games filters routines
    function  ScanMainFilter(ROM_ID: Integer): Boolean;
    function  CheckParentalLock(romID: Integer; GameName: String): Boolean;
    function  FilterGamesList(FilterName: String): Boolean;
    // games filters routines

    function  GetControlTypeIndex(const ControlName: String): Integer;
    function  CreateGamesListXML(sysID: ShortInt): Boolean;
    function  CreateGamesListZiNc: Boolean;
    function  CreateGamesListDaphne: Boolean;
    function  VerifyMultiSelect: Boolean;
    function  GetFavoriteUserFileName(UserName: String): String;
    function  AddToFavorite: Boolean;
    function  DeleteFromFavorite: Boolean;
    function  Check_ROMsData_File(SystemID: Integer): Boolean;
    function  RefreshGames(GamesList1: THashedStringList; GamesList1Position: Integer; SingleGame: Boolean = False): Boolean;

    function  StopRefreshAllGames: Boolean;
    function  StopBuildDatabase(tempInfo:String): Boolean;

    //function  ReadSelectedGamePlayTime(romID: Integer; GameName: String): String;
    procedure UpdateSelectedGamePlayTime(romID: Integer; GameName: String; TotalPlayTime: Int64);

    procedure CallDeleteFile(FileName, Folder: String);

    procedure WMSystemCommand(var Msg: TWMSysCommand);  message WM_SYSCOMMAND; // Full Screen Mode
    procedure SetAudit(SysID: ShortInt; AuditID: ShortInt);

    procedure ShowGameInfoAll(InfoIndex: ShortInt; AutoGameInfo: Boolean = False);
    function  GetSaveStateFileName: String;
    function  GetInputFileName(Recording: Boolean = False): String;
    procedure ToggleFavoriteLastFilter;
    procedure SetLayoutGameDocuments;
    { Private declarations }
  public
    //MemGameInfo: TGameInfo;
    WinQuotesStr: String[1];
    CompleteGamesList, ZipErrors: THashedStringList;
    SystemID_Number{, SelectedGame, }: Integer;
    SelectedFilterName, LastFilterName: String;
    SelectedNode: PVirtualNode;
    GameInfoData: pGameInfo;
    //ScreenshotFileName: String;

    ColumnsSort: packed array[0..MaxArcadeSystems] of packed array[0..1] of ShortInt;
    ColumnsProfile,
    SelectedGameName: packed array[0..MaxArcadeSystems] of String;
    SelectedGameID: packed array[0..MaxArcadeSystems] of Integer;
    ColumnsPosList: array of ShortInt;

    EmulatorFile,
    EmulatorVersion,
    EmulatorChecksum: packed array[1..MaxArcadeSystems] of String;

    emuROMsFolders: packed array[1..MaxArcadeSystems] of THashedStringList;
    imgFolderZipFile: packed array[1..MaxArcadeSystems] of packed array[0..11] of String;

    FrontendPath, FavoriteUser, FavoriteUserFile: String;
    NoScreenshotLoaded, CancelCurrentOperation, AbortExecution: Boolean;

    CategoriesList, GamePlayTime: TMemIniFile;

    mImageIndex: Integer;
    mROMIdentification: Integer;
    mMediaType: ShortInt;

    mGameSize: String;
    mBiosName: String;
    mAudioSampleName: String;
    mSaveState: ShortInt;

    // columns order
    mDescription: String;
    mYear: String[4];
    mManufacturer: String;
    mAudioChannels: ShortInt;
    mAudioSamples: ShortInt;

    mControlType: ShortInt;
    mControls: String;

    mNumberScreens: ShortInt;

    mScreenType1: ShortInt;
    mScreenRotation1: SmallInt;
    mResolutionWidth1: SmallInt;
    mResolutionHeight1: SmallInt;
    mRefreshRate1: String;

    mScreenType2: ShortInt;
    mScreenRotation2: SmallInt;
    mResolutionWidth2: SmallInt;
    mResolutionHeight2: SmallInt;
    mRefreshRate2: String;

    mScreenType3: ShortInt;
    mScreenRotation3: SmallInt;
    mResolutionWidth3: SmallInt;
    mResolutionHeight3: SmallInt;
    mRefreshRate3: String;

    mScreenType4: ShortInt;
    mScreenRotation4: SmallInt;
    mResolutionWidth4: SmallInt;
    mResolutionHeight4: SmallInt;
    mRefreshRate4: String;

    mDriverStatus: ShortInt;
    mEmulationStatus: ShortInt;
    mColorStatus: ShortInt;
    mSoundStatus: ShortInt;
    mGraphicStatus: ShortInt;
    mCocktailStatus: ShortInt;
    mProtectionStatus: ShortInt;

    mCategory: String;
    mVersionAdded: String[20];
    mName: String;
    mClone: String;
    mDriverName: String;
    mMerged: String[5];
    mPlayTime: String;
    mPlayed: Integer;
    mNumberPlayers: String;

    ctrlrDir: String;
    IniFilesDir, SaveStateDir, InputDir,
    AudioFolders, MNGFolders: packed array[1..MaxArcadeSystems] of String;
    ImageType: ShortInt;

    ListROMsName, ListROMsSize, ListROMsCRC, ListROMsNameFullPath,
    ParentListROMsName, ParentListROMsSize, ParentListROMsCRC, ParentListROMsNameFullPath: THashedStringList;

    Auditing: Boolean;
    AutoMAMEInfoDATFile, AutoHistoryDATFile, AutoStoryDATFile, ParentalLockGamesList: THashedStringList;
    ParentalLockPasswordString, LogoFileName: String;

    Filter1Name: String;
    FavList: THashedStringList;

    // BcMenus functions
    procedure DrawGradient(Canvas: TCanvas; ARect: TRect; StartingColor,
      EndingColor: TColor; Style: TGradientStyle);

    function  ValidateParentalLockPassword(PasswordString: String; PasswordType: SmallInt): Boolean;

    function  LoadPreferencesIcons: Boolean;

    // FMOD procedures
    function  InitDeInitFMOD(FMODStatus, ReloadDLL, RunningGame: Boolean): Boolean;
    procedure PopulateDevices;
    procedure SetVolume(VolumeValue: Integer);
    // FMOD procedures

    procedure BlendWindow(HolderWindow: ShortInt;BlendFactor: Byte);

    function  GetGameData(tNodeIndex: PVirtualNode): Boolean;

    function  MountControlTypesList(const StringHolder: String; ListViewHolder: TListView; GetFirstControlOnly: Boolean = False): String;

    procedure ClearMemoryColumnsVariables;
    function  PopulateROMDataLine: String;
    function  AddGames(const FilterName: String; SelectItem: Boolean): Boolean;
    function  LoadListCPU(BoxHolder: TComboBox): Boolean;

    procedure UpdateProgressLabel(Position, Total: Integer);

    function  IsThemesEnabled: Boolean;
    function  ValidateFile(FileName: String): Boolean;
    function  CheckReadOnly(const FileString: String): Boolean;

    procedure UpdateMAMEsnapDir(dirString: String; SystemID: ShortInt);
    procedure DialogOpenFile(FilterType: ShortInt; const DialogTitle: String; EditHolder: TEdit; MultipleFiles, GraphicImage: Boolean; const DefaultDirectory: String = '');
    procedure DialogSelectFolder(EditHolder: TEdit; MultipleFolders: Boolean);
    procedure DialogSelectMultiFolders(ListHolder: TListBox; SubFolders: Boolean; HashedList: THashedStringList = nil);

    function  IsSystemEntry(SystemName: String): Boolean;
    procedure SetAlphaBlendTreeView(TreeViewHolder: TVirtualStringTree);
    procedure ClearTreeView(TreeViewHolder: TVirtualStringTree);
    function  CheckSelected(TreeViewHolder: TVirtualStringTree): Boolean;
    function  CheckTotal(TreeViewHolder: TVirtualStringTree): Boolean;
    function  CheckTotalVisible(TreeViewHolder: TVirtualStringTree): Boolean;
    procedure ApplyFilters(FilterName: String; SelectItem: Boolean);
    procedure SetGameType(FilterName: String; LoadFiles: Boolean);
    function  GameIsClone(const CloneName: String): Boolean;
    procedure ExecuteGame(RunMode: ShortInt);
    procedure SetDescriptionFormat;
    function  FillGamePlayTime: Boolean;
    procedure SetGamePlayTime_Played;

    procedure UpdateStatusBarGame;
    function  SearchZIP(const GameName: String; romID: Integer = -1): Boolean;
    function  SearchZIPFolder(const GameName: String; romID: Integer = -1): String;
    function  SearchCHDFolder(DiskImageFileName: String; RunningGame: Boolean; romID: Integer = -1): String;
    function  FoundMerged(GameName, OriginalGameName, FilePath: String): Boolean;

    function  RunProcess(AppPath: String; MustWait: Boolean=False;
                         Visibility: Word=SW_SHOWNORMAL; RunningGame: Boolean=True): DWORD;

    function  RemoveQuotes(const DataString: String): String;
    procedure LoadFolders_MAME(SystemID: Integer);
    procedure LoadFoldersConsole(sysID: Integer);
    procedure LoadFoldersAllSystems;
    function  SearchSampleZip(GameName, SampleName: String; sysID: ShortInt): Boolean;
    function  UpdateSampleInfo(GameName, SampleName: String; sysID: ShortInt): Boolean;

    procedure UpdateImageTypeDescriptionComboBoxEx(ComboBoxExHolder: TComboBoxEx);
    procedure LoadTopBar(ImageHolder: TImage32; FileName: String);
    procedure LoadFrontendIcons;
    function  GetGameIcon(IL_LargeHolder, IL_StandardHolder, IL_SmallHolder: TImageList; Index: Integer; IconHolder: TIcon): Boolean;
    procedure SetIcon(SourceHolder, DestHolder: TImageList; SourceIndex, DestIndex: Integer);
    procedure GetROMFields(ListHolder: THashedStringList; Index: Integer);
    procedure GetGameROMs(ListHolder: THashedStringList; Auditing: Boolean);
    procedure ClearEmulatorVariables(SystemID: Integer);
    procedure ClearImageInfo(ScreenIndex: ShortInt); // new function
    function  MountResolution(Width, Height, Rotation: SmallInt; FixOutput: Boolean = True): String;
    function  MountOrientation(Rotation: SmallInt): String;
    function  GetEmulatorVersion(SystemID: Integer; const FileName: String; out StoreResultIn: String): Boolean;
    procedure SetSelectedColorBox(ColorBoxHolder: TColorBox; Color: TColor);
    procedure FixEmptyValue(TextHolder: TEdit; StringValue: String);
    function  GetBatchFileFieldIndex(ParameterIndex: String): String;

    function  SelectImageMenu(MenuName: TMenuItem; ImageColorBox: TColorBox): Boolean;

    function  ReadIniFile(out ErrorString: String): Boolean;
    procedure UpdateIniFile(EmulatorsOnly: Boolean);

    function  GetMAMEIniFileName(EmulatorFileName: String; SystemID: Integer): String;
    function  GetMAMECustomIniFileName(EmulatorFileName, GameName: String; SystemID: Integer): String;
    function  CheckAllMAMEIniFiles(out ErrorString: String): Boolean;

    function  ReadCustomCommandLine(sFileName: String; romID: Integer; RunningGame: Boolean = False): String;
    function  GenerateParams(pIndex: ShortInt; ListViewHolder: TListView): String;
    procedure WriteCustomCommandLine(sFileName, sEmulatorFile: String; sParameters: TListView; sAdditionalParameters: String; romID, PrefixLeadingSpace: Integer);
    procedure DeleteCustomCommandLine(sFileName: String; romID: Integer);

    function  Get_DOSBox_Status(RunningGame: Boolean): Word;
    function  CheckMAMEIniFile(EmulatorFileName: String; SystemID: Integer): Boolean;
    procedure CreateMAMEIniFile(EmulatorFileName: String);

    function  GetFolderZiNc_cfg: String;
    procedure ReadZiNc_cfg(FileName: String; CustomGameSettings: Boolean);
    procedure UpdateZiNc_cfg(FileName: String; CustomGameSettings: Boolean);

    procedure SetCustomOptions(GameName: String; Driver: Boolean);
    procedure DeleteCustomOptions(GameName: String);

    procedure AddControllerDefinitionsMenuItems(EmulatorFileName: String);
    procedure AddMenuItem(MenuHolder: TMenuItem; Description, HintName: String; Duplicate: Boolean);

    procedure CallEmulatorOptions(EmulatorFileName: String; sysID: ShortInt);
    procedure ExtractROMsFolders(ROMsList: String; SystemID: Integer; ListHolder: TListBox = nil);
    function  MountFoldersList(ListHolder: TListBox): String;

    procedure SetAspectRatio;
    procedure UpdateLabelImages;

    function  GetImageName(GameName: String; ImageIndex: ShortInt; FormatIndex: ShortInt): String;

    procedure CycleImageType;
    procedure InvertCycleImageType;
    function  ButtonViewImage(ButtonCode: ShortInt): Boolean;
    function  VerifyZipType(ZipString: String; GetFolder: Boolean; FullZipPath: Boolean = False): String;
    function  GetZipFolderFull(FolderType: ShortInt; SystemID: Integer = -1): String;
    function  GetImageTypeZIPFilename(ImageType: ShortInt; SystemID: Integer = -1): String;
    function  SetScreenAspectRatio(ResWidth, resHeight: Integer; out FixedWidth, FixedHeight: Integer): Boolean;
    procedure ClearImage;
    function  DisplayImage(romID: Integer; GameName, CloneGameName: String; ImageHolder: TImage32; ImageType: Integer; CloseZIP: Boolean; ScreenIndex: ShortInt): Boolean;

    function  LoadImageFromStream(StreamHolder: TMemoryStream; ImageHolder: TImage32; ImageType: ShortInt; ImageFileName: String; ScreenIndex: ShortInt): Boolean;

    function  GetGameInfo(GameName: String; el_List: THashedStringList): Integer;
    procedure CallRefreshGames(RefreshMode: ShortInt; CreatingList: Boolean; sysID: Integer);

    function  SearchString(const SubString, StringLine: String): Boolean;
    function  GetSizeType(Value: Extended; Bits: Boolean): ShortString;
    function  UpdateGameSize: String;
    procedure UpdateTotalEntriesLabel;

    // ZIP functions
    procedure ShowZipErrors;
    procedure AddBadZip(const ZipFile, FileName: String; ErrorIndex: ShortInt);
    function  GetContents(ZipFileName: String; DeleteList, DeleteParentList: Boolean): Boolean;
    function  UnZipFile(ZipFileName, ROMFileName: String): Boolean;
    function  UnZipFileMemory(ZipFileName, ROMFileName: String; StreamHolder: TMemoryStream; FileIndex: Integer = -1): Boolean;

    function  DeleteFileInsideZip(ZipFileName, DelFileName: String): Boolean;
    function  DeleteExtraFileInsideZip(ZipFileName, DelFileName: String): Boolean;
    function  RenameFileInsideZip(ZipFileName, CurrentName, NewName: String): Boolean;
    function  ExtractFilesList(ZipFileName, FilesUnzip: String): Boolean;

    function  FixCaption(const CaptionString: String): String;

    // Columns visibility procedures
    function  SetColumnsMemList(IniFileName: TMemIniFile): Boolean;
    procedure ReadColumnProfile;
    procedure UpdateColumnProfile(UpdateColumns, WriteProfileINI: Boolean);

    function  CheckDefaultIconsFile: Boolean;
    function  SetToolBarIcon(IconFileName, IconFolder: String; IconList: TImageList; IconIndex: Integer; DisplayErrorMsg: Boolean = True): Boolean;
    function  AddDefaultIcons(IconFileName, IconsFolder: String; IconList: TImageList): Boolean;
    function  AddMainScrIcons(IconFileName, IconsFolder: String; IconListLarge, IconListSmall: TImageList; Reload: Boolean): Boolean;
    function  AddGameIcons(IconFileName, IconsFolder: String): Boolean;
    function  AddMAMu_Icon(romID: Integer; GameName, CloneName: String; IconList: TImageList): Integer;

    function  LoadFavUserIcon128(IconFileName: String; ImageHolder: TImage): Boolean;
    function  GetFavoritesFolder: String;
    function  GetColumnsProfileFolder: String;

    procedure ReadDefaultIconsFile;

    // Virtual TreeView functions
    function  FindNodeGame(GameDescription: String): PVirtualNode;
    function  FindNodeGameName(GameName: String; SystemID: ShortInt): PVirtualNode;
    procedure SelectNode(ItemIndex: Integer);

    function  SetLockedGamesList(Mode: Boolean): Boolean;
    function  FullFolderFix(const FolderString: String): String;
    function  FullEmuFolderFix(const FolderString: String; SysID: Integer): String;
    function  GetEmuFullDescription(SystemID: Integer): String;
    function  GetSystemFolderName(romID: Integer): String;
    function  GetSystemID(romID: Integer): Integer;
    function  GetSystemIniSection(const SystemID: Integer): String;
    function  FillEmuDescriptionsSelector(const ComboBoxExHolder: TComboBoxEx): Boolean;

    function  GetStatusMessage(MsgCode: String): String;
    procedure ScanMissingImages(sysID: Integer; AddTitle: Boolean = False; CloseHTML: Boolean = False);

    property DrawBuffer: TBitmap read GetDrawBuffer;
    { Public declarations }
  end;

var
  FormMain: TFormMain;

implementation

uses uPreferences, uStatus,
     uAuditGames, uAbout, uTextViewer, uMessageBox,
     uGameDetails, uEmulatorsSetup, uParentalLockEditor,
     uParentalLockPasswordLogout, uFilesUtil,
     fmoddyn, fmoderrors, uRandomGamePreviewPanel,
     uZiNcSettings, uToolBarEditor, uImagesToolBarEditor,
     uMAMu_MaintenanceSettings, uFavoriteGamesProfileEditor,
     uLoadSaveState, uBiosSet, uControllerKeysLayout, uArcadeGamesFilter,
     uNotUsed, uMissingImages, uCustomGamesEditor, uColumnsEditor,
     uLoadInputFile, uMAMESettings, uCustomCommandLine,
     uStatusBarEditor, uConvertImages, uDeleteMultipleGamesFiles;

const
  MusicTypes: packed array [TFMusicTypes] of String =
    ('None', 'Protracker/FastTracker', 'ScreamTracker 3', 'FastTracker 2', 'Impulse Tracker', 'Midi', 'FMOD Sample Bank');

const
  OutputTypes: packed array [0..2] of TFSoundOutputTypes =
    (FSOUND_OUTPUT_WINMM, FSOUND_OUTPUT_DSOUND, FSOUND_OUTPUT_A3D);
  OutputRates: packed array [0..4] of Integer = (8000, 11025, 22050, 44100, 48000);

{$R *.dfm}

function TFormMain.GetDrawBuffer: TBitmap;
begin
  if not Assigned(FDrawBuffer) then
    FDrawBuffer := TBitmap.Create;
  Result := FDrawBuffer;
end;

procedure TFormMain.DrawGradient(Canvas: TCanvas; ARect: TRect; StartingColor,
  EndingColor: TColor; Style: TGradientStyle);
begin
  DrawBuffer.Height:= RectHeight(ARect);
  DrawBuffer.Width:= RectWidth(ARect);
  BarMenus.DrawGradient(DrawBuffer, nil, BitmapRect(DrawBuffer), startingColor, EndingColor, Style);
  Canvas.Draw(ARect.Left, ARect.Top, DrawBuffer); // copy the buffer
  DrawBuffer.Height:= 0;
  DrawBuffer.Width:= 0;
end;

procedure TFormMain.PopulateDevices;
var
  DriverCount: Integer;
  Driver: Integer;
begin
  FormPreferences.OutputDevice.Items.Clear;
  DriverCount:= FSOUND_GetNumDrivers;
  if DriverCount > 0 then
  begin
    for Driver:= 0 to DriverCount - 1 do
      FormPreferences.OutputDevice.Items.Add(FSOUND_GetDriverName(Driver));
    FormPreferences.OutputDevice.ItemIndex:= 0;
  end;
end;

procedure TFormMain.SetVolume(VolumeValue: Integer);
begin
  FormPreferences.LabelAudioVolumeValue.Caption:= Format('%3.3d', [FormPreferences.AudioVolume.Position]);
  if FormPreferences.PlayAudio.Checked then
     begin
       if FSongs[0].Module <> nil then
          FMUSIC_SetMasterVolume(FSongs[0].Module, FormPreferences.AudioVolume.Position)
       else
       if FSongs[0].Stream <> nil then
          FSOUND_SetVolume(FSongs[0].Channel, FormPreferences.AudioVolume.Position);
     end;
end;

function TFormMain.InitDeInitFMOD(FMODStatus, ReloadDLL, RunningGame: Boolean): Boolean;
var
  Index: Integer;
begin
  Result:= True;
  case FMODStatus of
    True:
      begin
        if ReloadDLL then
           begin
             if not FMOD_Load() then
                begin
                  GenerateMessage('File Not Found', 'File "fmod.dll" could not be loaded! Make sure file "fmod.dll" exists.', 2);
                  Result:= False;
                  FormPreferences.PlayAudio.Checked:= False;
                  Exit;
                end;
           end;
        { Check version numbers }
        if FMOD_VERSION > FSOUND_GetVersion then
           begin
             GenerateMessage('Version Mismatch', Format('API version %3.2f is newer than DLL version %3.2f', [FMOD_VERSION, FSOUND_GetVersion]), 2);
             Result:= False;
             FormPreferences.PlayAudio.Checked:= False;
             Exit;
           end;

        { Initialize FSOUND }
        try
          if not FSOUND_SetOutput(FSOUND_OUTPUT_WINMM) then
             begin
               GenerateMessage('Error [FSOUND_SetOutput]',
                               Format('Failed to initialize "%s" output!',
                                      ['Windows Multimedia WaveOut']), 2);
               Result:= False;
               FormPreferences.PlayAudio.Checked:= False;
               Exit;
             end;
          if FormPreferences.OutputDevice.Items.Count > 0 then
             Index:= FormPreferences.OutputDevice.ItemIndex
          else
             Index:= FormPreferences.OutputDevice.Tag;

          if Index = -1 then
             Index:= 0;

          if not FSOUND_SetDriver(Index) then
             begin
               GenerateMessage('Error [FSOUND_SetDriver]',
                               Format('Failed to initialize "%s" sound driver! Try selecting another driver.',
                                      [FormPreferences.OutputDevice.Items[Index]]), 2);
               Result:= False;
               FormPreferences.PlayAudio.Checked:= False;
               Exit;
             end;

          if not FSOUND_SetMixer(TFSoundMixerTypes(FormPreferences.MixerType.ItemIndex)) then
             begin
               GenerateMessage('Error [FSOUND_SetMixer]',
                               Format('Failed to initialize "%s" sound mixer! Try selecting another mixer.',
                                      [FormPreferences.MixerType.Items[FormPreferences.MixerType.ItemIndex]]), 2);
               FormPreferences.PlayAudio.Checked:= False;
               Result:= False;
               Exit;
             end;

          if not FSOUND_SetHWND(Handle) then
             begin
               GenerateMessage('Error [FSOUND_SetHWND]', 'Failed to set window handle! Try restarting the frontend or even the operation system.', 2);
               Result:= False;
               FormPreferences.PlayAudio.Checked:= False;
               Exit;
             end;
        except
          GenerateMessage('Initialization', FMOD_ErrorString(FSOUND_GetError), 2);
          Result:= False;
          FormPreferences.PlayAudio.Checked:= False;
          Exit;
        end;

        if not FSOUND_Init(OutputRates[FormPreferences.OutputRate.ItemIndex], 128, 0 or FSOUND_INIT_GLOBALFOCUS or FSOUND_INIT_ACCURATEVULEVELS) then
           begin
             GenerateMessage('Error [FSOUND_Init]',
                             FMOD_ErrorString(FSOUND_GetError), 2);
             Result:= False;
             FormPreferences.PlayAudio.Checked:= False;
             Exit;
           end;

        { Initialize song list to empty }
        for Index:= 0 to 1 do
        begin
          FSongs[Index].Module:= nil;
          FSongs[Index].Stream:= nil;
          FSongs[Index].Channel:= -1;
        end;
      end;
    False:
      begin
        if FormPreferences.FMODSettings.Tag = 1 then
           begin
             FMUSIC_StopAllSongs();
             if FSongs[0].Playing then
                StopSound;
             for Index:= 0 to 1 do
             begin
               if FSongs[Index].Module <> nil then
                  FMUSIC_FreeSong(FSongs[Index].Module)
               else
               if FSongs[Index].Stream <> nil then
                  begin
                    FSOUND_Stream_Stop(FSongs[Index].Stream);
                    FSOUND_Stream_Close(FSongs[Index].Stream);
                  end;
             end;
             FSOUND_Close;
             if ReloadDLL then
                FMOD_UnLoad;
           end;
      end;
  end;
end;

procedure TFormMain.LoadSound(romID: Integer; MasterName, CloneName: String);
var
  Stream: PFSoundStream;
  Module: PFMusicModule;
  SndFileName: String;
  OpenMode: Cardinal;

  function FoundGameFile(audioExtention: String): Boolean;
  begin
    Result:= True;
    case FileExists(SndFileName+MasterName+audioExtention) of
      True: SndFileName:= SndFileName+MasterName+audioExtention;
      False:
        begin
          if FormPreferences.AudioVideoUseParent.Checked then
             begin
               case GameIsClone(CloneName) of
                 True:
                   begin
                     case FileExists(SndFileName+CloneName+audioExtention) of
                       True : SndFileName:= SndFileName+CloneName+audioExtention;
                       False: Result:= False;
                     end;
                   end;
                 False: Result:= False;
               end;
             end;
        end;
    end;
  end;

  function SearchSoundFile: Boolean;
  begin
    Result:= False;
    SndFileName:= '';
    GetSystemID(romID);
    SndFileName:= IncludeTrailingPathDelimiter(FullFolderFix(AudioFolders[SystemID_Number]));

    if FormPreferences.AudioFormatMP3.Checked then
       Result:= FoundGameFile('.mp3');
    if not Result and FormPreferences.AudioFormatWAV.Checked then
       Result:= FoundGameFile('.wav');
    if not Result and FormPreferences.AudioFormatOGG.Checked then
       Result:= FoundGameFile('.ogg');
  end;

begin
  if FSongs[0].Playing then
     StopSound;

  if SearchSoundFile then
     begin
       TimerFMOD.Enabled:= True;
       Stream:= nil;
       Module:= FMUSIC_LoadSong(PChar(SndFileName));
       if Module = nil then
          begin
             case FormPreferences.AudioVideoLoop.Checked of
               True : OpenMode:= FSOUND_NORMAL or FSOUND_LOOP_NORMAL;
               False: OpenMode:= FSOUND_NORMAL or FSOUND_LOOP_OFF;
             end;
             if LowerCase(ExtractFileExt(SndFileName)) = '.mp3' then
                OpenMode:= OpenMode or FSOUND_MPEGACCURATE;
             Stream:= FSOUND_Stream_Open(PChar(SndFileName), OpenMode, 0, 0);
          end;

       if (Module = nil) and (Stream = nil) then
          GenerateMessage('Load Error', FMOD_ErrorString(FSOUND_GetError), 2);

       if Module <> nil then
          begin
            FMUSIC_SetMasterVolume(Module, FormPreferences.AudioVolume.Position);
            if (FMUSIC_GetType(Module) = FMUSIC_TYPE_MOD) or (FMUSIC_GetType(Module) = FMUSIC_TYPE_S3M) then
             FMUSIC_SetPanSeperation(Module, 0.15);  // 15% crossover
          end;

       FSongs[0].Module:= Module;
       FSongs[0].Stream:= Stream;
       FSongs[0].Playing:= False;
       PlaySound;
     end;
end;

procedure TFormMain.PlaySound;
begin
  if FSongs[0].Module <> nil then
     begin
       FSongs[0].Playing:= FMUSIC_PlaySong(FSongs[0].Module);
       if not FSongs[0].Playing then
          GenerateMessage('Play Song', FMOD_ErrorString(FSOUND_GetError), 2);
     end
  else
  if FSongs[0].Stream <> nil then
     begin
       FSongs[0].Channel:= FSOUND_Stream_Play(FSOUND_FREE, FSongs[0].Stream);
       FSongs[0].Playing:= FSongs[0].Channel >= 0;
       if not FSongs[0].Playing then
          GenerateMessage('Play Stream', FMOD_ErrorString(FSOUND_GetError), 2)
       else
          begin
            FSOUND_SetPan(FSongs[0].Channel, FSOUND_STEREOPAN);
            FSOUND_SetVolume(FSongs[0].Channel, FormPreferences.AudioVolume.Position);
          end;
     end;
end;

procedure TFormMain.StopSound;
begin
  if FSongs[0].Module <> nil then
     FMUSIC_StopSong(FSongs[0].Module)
  else
  if FSongs[0].Stream <> nil then
     FSOUND_Stream_Stop(FSongs[0].Stream);

  FSongs[0].Channel:= -1;
  FSongs[0].Playing:= False;
  TimerFMOD.Enabled:= False
end;

procedure TFormMain.BlendWindow(HolderWindow: ShortInt; BlendFactor: Byte);
begin
  case HolderWindow of
    0:
      begin
        if Assigned(FormRandomGamePreviewPanel) then
           FormRandomGamePreviewPanel.AlphaBlendValue:= BlendFactor;
      end;
  end;
end;

procedure TFormMain.FreeMemoryZipContents(SystemID: Integer = -1);
var
  Loop: Integer;
begin
  if GamesTreeView.Tag = 0 then
     Exit;
  if SystemID = -1 then
     begin
       for Loop:=1 to MaxArcadeSystems do
       begin
         if Assigned(imgZipContents[Loop]) then
            begin
              FreeAndNil(imgZipContents[Loop]);
              FreeAndNil(imgZipContentsFullPath[Loop]);
            end;
       end;
     end
  else
     begin
       if Assigned(imgZipContents[SystemID]) then
          begin
            FreeAndNil(imgZipContents[SystemID]);
            FreeAndNil(imgZipContentsFullPath[SystemID]);
          end;
     end;
end;

function TFormMain.GetSizeType(Value: Extended; Bits: Boolean): ShortString;

  function FormatText(Value: Extended): String;
  begin
    if Value = 0 then
       Result:= '0'
    else
    if Pos('.0', FloatToStr(Value)) <> 0 then
       Result:= TrimLeft(Format('%3u', [Trunc(Value)]))
    else
    if Pos('.', FloatToStr(Value)) <> 0 then
       Result:= TrimLeft(Format('%3.2f', [Value]))
    else
       Result:= TrimLeft(Format('%3u', [Trunc(Value)]));
  end;

begin
  if Bits then
     Value:= Value * 8; // convert bytes to bits

  if Trunc(Value / 1024) > 0 then
     begin
       Value:= Value / 1024; // convert bits to Kb
       if Trunc(Value / 1024) > 0 then
          begin
            Value:= Value / 1024; // convert Kb to Mb
            if Trunc(Value / 1024) > 0 then
               begin
                 Value:= Value / 1024; // convert Mb to Gb
                 Result:= FormatText(Value)+' G';
               end
            else
               Result:= FormatText(Value)+' M';
          end
       else
          Result:= FormatText(Value)+' K';
     end
  else
     Result:= FormatText(Value)+' ';

  case Bits of
    True : Result:= Result+'bits';
    False: Result:= Result+'Bytes';
  end;
end;

function TFormMain.UpdateGameSize: String;
var
  GameSize: Extended;
begin
  Result:= '';
  if not CheckSelected(GamesTreeView) then
     Exit;

  if not GetGameData(SelectedNode) then
     Exit;

  if GameInfoData.eGameSize = '' then
     begin
       case IsSystemEntry(GameInfoData.eDriverName) of
         True : Result:= '';
         False: Result:= 'Unknown';
       end;
       Exit;
     end
  else
     GameSize:= StrToFloat(GameInfoData.eGameSize);

  case MenuGameSizeFormat.Tag of
    0: Result:= GetSizeType(GameSize, True);
    1: Result:= GetSizeType(GameSize, False);
    2:
     begin
       // get the .zip file size
       if mMerged = '' then
          GameSize:= GetFileSize(SearchZIPFolder(GameInfoData.eName, GameInfoData.eROMIdentification))
       else
          begin
            GetSystemID(GameInfoData.eROMIdentification);
            case SystemID_Number of
              1, 4, 5:
                begin
                  if GameIsClone(GameInfoData.eClone) then
                     GameSize:= GetFileSize(SearchZIPFolder(GameInfoData.eClone, GameInfoData.eROMIdentification));
                end;
              2, 3: GameSize:= GetFileSize(SearchZIPFolder(GameInfoData.eName, GameInfoData.eROMIdentification));
            end;
          end;

       if GameSize = -1 then
          GameSize:= 0;
       Result:= GetSizeType(GameSize, False);
     end;
  end;
end;

procedure TFormMain.UpdateTotalEntriesLabel;
begin
  StatusBar_TotalEntries.Caption:= Format('Tot. Entries %.5u', [GamesTreeView.VisibleCount]);
end;

procedure TFormMain.ShowZipErrors;
begin
  if (Assigned(ZipErrors)) and (ZipErrors.Count > 0) and (FormPreferences.ShowZipErrorMessages.Checked) then
     GenerateZipErrorsMessage('Error Handling Zip Files', ZipErrors);
  FreeAndNil(ZipErrors);
end;

procedure TFormMain.AddBadZip(const ZipFile, FileName: String; ErrorIndex: ShortInt);
var
  AddFile: Boolean;
  MsgString: String;
begin
  if ZipFile <> '' then
     begin
       case Assigned(ZipErrors) of
         True: AddFile:= (ZipErrors.IndexOf(ZipFile) = -1);
         False:
           begin
             ZipErrors:= THashedStringList.Create;
             AddFile:= True;
           end;
       end;
       if AddFile then
          begin
            case ErrorIndex of
              0: MsgString:= 'Failed to get file contents'; // get contents
              1: MsgString:= Format('Failed to unzip "%s" to disk', [FileName]); // unzip file
              2: MsgString:= Format('Failed to unzip "%s" to memory stream', [FileName]); // unzip file to memory
              3: MsgString:= Format('Failed to delete "%s" from zip', [FileName]); // delete file insize zip
              4: MsgString:= Format('Failed to delete extra files of "%s" from zip', [FileName]); // delete extra files inside zip
              5: MsgString:= Format('Failed to rename "%s" in zip', [FileName]); // rename file inside zip
              6: MsgString:= 'Failed to extract files';// extract all files
            end;
            MsgString:= MsgString+' ['+ZipFile+'].';
            ZipErrors.Add(MsgString);
          end;
     end;
end;

function TFormMain.GetContents(ZipFileName: String; DeleteList, DeleteParentList: Boolean): Boolean;
var
  ArchiveItem: TZFArchiveItem;
begin
  AddParentSet:= DeleteParentList;
  if DeleteList then
     begin
       if Assigned(ListROMsName) then
          ListROMsName.Clear;
       if Assigned(ListROMsSize) then
          ListROMsSize.Clear;
       if Assigned(ListROMsCRC) then
          ListROMsCRC.Clear;

       if Assigned(ListROMsNameFullPath) then
          ListROMsNameFullPath.Clear;
     end;

  if DeleteParentList Then
     begin
       if Assigned(ParentListROMsName) then
          ParentListROMsName.Clear;
       if Assigned(ParentListROMsSize) then
          ParentListROMsSize.Clear;
       if Assigned(ParentListROMsCRC) then
          ParentListROMsCRC.Clear;
       if Assigned(ParentListROMsNameFullPath) then
          ParentListROMsNameFullPath.Clear;
     end;

  with ZipForge do
  begin
    FileName:= ZipFileName;

    // Open existing archive file
    try
      OpenArchive(fmOpenRead);

      Result:= FileCount > 0;
      if Result then
         begin
           // Search text files stored inside the archive
           if FindFirst('*.*', ArchiveItem) then
              begin
                case AddParentSet of
                  False:
                    begin
                      repeat
                        if Assigned(ListROMsName) then
                           ListROMsName.Add(AnsiLowerCase(ArchiveItem.FileName));
                        if Assigned(ListROMsSize) then
                           ListROMsSize.Add(IntToStr(ArchiveItem.UncompressedSize));
                        if Assigned(ListROMsCRC) then
                           ListROMsCRC.Add(LowerCase(Format('%.8x', [ArchiveItem.CRC])));
                        if Assigned(ListROMsNameFullPath) then
                           ListROMsNameFullPath.Add(AnsiLowerCase(AnsiLowerCase(ArchiveItem.StoredPath+ArchiveItem.FileName)));
                      until (not FindNext(ArchiveItem));
                    end;
                  True:
                    begin
                      repeat
                        if Assigned(ParentListROMsName) then
                           ParentListROMsName.Add(AnsiLowerCase(ArchiveItem.FileName));
                        if Assigned(ParentListROMsSize) then
                           ParentListROMsSize.Add(IntToStr(ArchiveItem.UncompressedSize));
                        if Assigned(ParentListROMsCRC) then
                           ParentListROMsCRC.Add(LowerCase(Format('%.8x', [ArchiveItem.CRC])));

                        if Assigned(ParentListROMsNameFullPath) then
                           ParentListROMsNameFullPath.Add(AnsiLowerCase(AnsiLowerCase(ArchiveItem.StoredPath+ArchiveItem.FileName)));
                      until (not FindNext(ArchiveItem));
                    end;
                end;
              end
           else
              Result:= False;
         end;
      CloseArchive;
      ZipForge.FileName:= '';
    except
      Result:= False;
      CloseArchive;
      ZipForge.FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, '', 0);
end;

function TFormMain.UnZipFile(ZipFileName, ROMFileName: String): Boolean;
begin
  with ZipForge do
  begin
    FileName:= ZipFileName;
    try
      OpenArchive(fmOpenRead);

      Result:= FileCount > 0;
      if Result then
         begin
           BaseDir:= FrontendPath+'temp';
           if VerifyTempDirectory then
              ExtractFiles(ROMFileName);
         end;
      CloseArchive;
      FileName:= '';
    except
      Result:= False;
      CloseArchive;
      FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, ROMFileName, 1);
end;

function TFormMain.UnZipFileMemory(ZipFileName, ROMFileName: String; StreamHolder: TMemoryStream; FileIndex: Integer = -1): Boolean;
begin
  with ZipForge do
  begin
    FileName:= ZipFileName;
    try
      OpenArchive(fmOpenRead);

      Result:= FileCount > 0;
      if Result then
         ExtractToStream(ROMFileName, StreamHolder);
      CloseArchive;
      FileName:= '';
    except
      Result:= False;
      CloseArchive;
      FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, ROMFileName, 2);
end;

function TFormMain.DeleteFileInsideZip(ZipFileName, DelFileName: String): Boolean;
begin
  with ZipForge do
  begin
    FileName:= ZipFileName;
    try
      OpenArchive(fmOpenReadWrite);

      Result:= FileCount > 0;
      if Result then
         DeleteFiles(DelFileName);
      CloseArchive;
      FileName:= '';
    except
      Result:= False;
      CloseArchive;
      FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, DelFileName, 3);
end;

function TFormMain.DeleteExtraFileInsideZip(ZipFileName, DelFileName: String): Boolean;
begin
  with ZipForge do
  begin
    FileName:= ZipFileName;
    try
      if not Active then
         begin
           //RepairArchive; // this repairs damaged archive (don't know why but this needs to be here)... huh ?
           OpenArchive(fmOpenReadWrite);
         end;

      Result:= FileCount > 0;
      if Result then
         begin
           DeleteFiles(DelFileName+'????.png', faAnyFile-faDirectory, DelFileName+'.png');
           DeleteFiles(DelFileName+'????.jpg', faAnyFile-faDirectory, DelFileName+'.jpg');
           DeleteFiles(DelFileName+'????.gif', faAnyFile-faDirectory, DelFileName+'.gif');
         end;
      CloseArchive;
      FileName:= '';
      FileMasks:= nil;
      ExclusionMasks:= nil;
    except
      Result:= False;
      CloseArchive;
      FileName:= '';
      FileMasks:= nil;
      ExclusionMasks:= nil;
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, DelFileName, 4);
end;

function TFormMain.RenameFileInsideZip(ZipFileName, CurrentName, NewName: String): Boolean;
begin
  with ZIPForge do
  begin
    FileName:= ZipFileName;
    try
      if not Active then
         begin
           //RepairArchive; // this repairs damaged archive (don't know why but this needs to be here)... huh ?
           OpenArchive(fmOpenReadWrite);
         end;

      Result:= FileCount > 0;
      if Result then
         begin
           if Pos('\', CurrentName) <> 0 then
              NewName:= ExtractFilePath(CurrentName)+NewName;
           RenameFile(CurrentName, NewName);
         end;

      //CloseArchive;
      FileName:= '';
    except
      Result:= False;
      CloseArchive;
      FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, CurrentName, 5);
end;

function TFormMain.ExtractFilesList(ZipFileName, FilesUnzip: String): Boolean;
begin
  with ZIPForge do
  begin
    FileName:= ZipFileName;
    try
      OpenArchive(fmOpenRead);

      Result:= (FileCount > 0);
      if Result then
         begin
           BaseDir:= FrontendPath+'temp';
           if VerifyTempDirectory then
              ExtractFiles(FilesUnzip);
         end;
      CloseArchive;
      BaseDir:= '';
      FileName:= '';
    except
      Result:= False;
      CloseArchive;
      BaseDir:= '';
      FileName:= '';
    end;
  end;
  if (not Result) and (FormPreferences.ShowZipErrorMessages.Checked) then
     AddBadZip(ZipFileName, '', 6);
end;

procedure TFormMain.ClearMemoryColumnsVariables;
begin
  mImageIndex:= -1;
  mROMIdentification:= -1;
  mMediaType:= 0;
  mDescription:= '';
  mYear:= '';
  mManufacturer:= '';
  mAudioChannels:= 0;
  mAudioSamples:= -1;
  mAudioSampleName:= '';
  mControls:= '';
  mControlType:= 0;

  mScreenType1:= -1;
  mScreenRotation1:= -1;
  mResolutionWidth1:= -1;
  mResolutionHeight1:= -1;
  mRefreshRate1:= '';

  mScreenType2:= -1;
  mScreenRotation2:= -1;
  mResolutionWidth2:= -1;
  mResolutionHeight2:= -1;
  mRefreshRate2:= '';

  mScreenType3:= -1;
  mScreenRotation3:= -1;
  mResolutionWidth3:= -1;
  mResolutionHeight3:= -1;
  mRefreshRate3:= '';

  mScreenType4:= -1;
  mScreenRotation4:= -1;
  mResolutionWidth4:= -1;
  mResolutionHeight4:= -1;
  mRefreshRate4:= '';

  mDriverStatus:= -1;
  mEmulationStatus:= -1;
  mColorStatus:= -1;
  mSoundStatus:= -1;
  mGraphicStatus:= -1;
  mCocktailStatus:= -1;
  mProtectionStatus:= -1;

  mCategory:= '';
  mVersionAdded:= '';
  mName:= '';
  mClone:= '';
  mDriverName:= '';
  mMerged:= '';
  mPlayTime:= '';
  mPlayed:= 0;
  mNumberPlayers:= '-1';
  mGameSize:= '';
  mBiosName:= '';
  mSaveState:= -1;
end;

procedure TFormMain.ClearImageInfo(ScreenIndex: ShortInt);
begin
  ImageDetails[ScreenIndex].FileName:= '';
  ImageDetails[ScreenIndex].ZipFileName:= '';
  ImageDetails[ScreenIndex].Size:= -1;
  ImageDetails[ScreenIndex].ResolutionX:= -1;
  ImageDetails[ScreenIndex].ResolutionY:= -1;
  ImageDetails[ScreenIndex].AspectRatioResolutionX:= -1;
  ImageDetails[ScreenIndex].AspectRatioResolutionY:= -1;
end;

function TFormMain.MountResolution(Width, Height, Rotation: SmallInt; FixOutput: Boolean = True): String;
begin
  if (Width <> -1) or (Height <> -1) then
     begin
       case FixOutput of
         True:
           begin
             case Rotation of
               0, 180: Result:= IntToStr(Width)+'x'+IntToStr(Height);
               1, 90, 270: Result:= IntToStr(Height)+'x'+IntToStr(Width);
             end;
           end;
         False: Result:= IntToStr(Width)+'x'+IntToStr(Height);
       end;
     end
  else
     Result:= '';
end;

function TFormMain.MountOrientation(Rotation: SmallInt): String;
begin
  case Rotation of
    -1: Result:= '';
    0, 180: Result:= aOrientation[0];
    1, 90, 270: Result:= aOrientation[1];
  end;
end;

function TFormMain.ValidateParentalLockPassword(PasswordString: String; PasswordType: SmallInt): Boolean;
var
  UncryptedPassword: String;
  PasswordFile: THashedStringList;
begin
  Result:= True;
  case PasswordType of
    0:
      begin
        case FileExists(ExtractFilePath(Application.ExeName)+'ini_files\parental_lock.ini') of
          True:
            begin
              PasswordFile:= THashedStringList.Create;
              PasswordFile.LoadFromFile(ExtractFilePath(Application.ExeName)+'ini_files\parental_lock.ini');
              Result:= PasswordFile.Count > 0;
              if Result then
                 begin
                   PasswordFile[0]:= DecryptData(PasswordFile.Strings[0]);
                   if PasswordFile.Names[0] = 'password' then
                      begin
                        UncryptedPassword:= PasswordFile.ValueFromIndex[0];
                        Result:= UncryptedPassword = PasswordString;
                      end
                   else
                      Result:= False;
                 end;
              FreeAndNil(PasswordFile);
            end;
          False: Result:= True;
        end;
      end;
    1:
      begin
        // it's for enter a new password, replacing the old one
      end;
  end;
end;

{function TFormMain.LoadParentalLockPassword: String;
var
  PasswordFile: THashedStringList;
begin
  Result:= '';
  PasswordFile:= THashedStringList.Create;
  PasswordFile.LoadFromFile(FrontendPath+'ini_files\parental_lock.ini');
  if PasswordFile.Count > 0 then
     begin
       PasswordFile[0]:= DecryptData(PasswordFile[0]);
       Result:= PasswordFile.ValueFromIndex[0];
       if Result = '' then
          GenerateMessage('Error', 'Could not extract password from "'+
                          FrontendPath+'ini_files\parental_lock.ini". Password not found!', 2);
     end;
  FreeAndNil(PasswordFile);
end;}

procedure TFormMain.ClearTreeView(TreeViewHolder: TVirtualStringTree);
begin
  TreeViewHolder.ClearSelection;
  TreeViewHolder.BeginUpdate;
  TreeViewHolder.Clear;
  TreeViewHolder.NodeDataSize:= -1;
  TreeViewHolder.RootNodeCount:= 0;
  TreeViewHolder.EndUpdate;
end;

function TFormMain.GetGameData(tNodeIndex: PVirtualNode): Boolean;
begin
  Result:= False;
  if GameInfoData <> nil then
     GameInfoData:= nil;
  if (not CheckSelected(GamesTreeView)) or (not CheckTotal(GamesTreeView)) then
     Exit;

  GameInfoData:= GamesTreeView.GetNodeData(tNodeIndex);
  Result:= GameInfoData <> nil;
end;

procedure TFormMain.InitializeColumnsSort;
var
  Loop: ShortInt;
begin
  // ColumnsSort[SystemID, 0] - Column Sorted
  // ColumnsSort[SystemID, 1] - Sort Direction
  // set 0 for Ascending
  // set 1 for Descending
  for Loop:=0 to MaxArcadeSystems do
  begin
    ColumnsSort[Loop, 0]:= 0; // column sorted
    ColumnsSort[Loop, 1]:= 0; // direction
  end;
end;

procedure TFormMain.InitializeEmulatorVariables;
var
  Loop, Loop2: Integer;
begin
  // define values for all arrays or exception error will occur....
  try
    for Loop:= 1 to MaxArcadeSystems do
    begin
      IniFilesDir[Loop]:= '';
      samplesDir[Loop]:= '';
      EmulatorFile[Loop]:= '';
      EmulatorVersion[Loop]:= '';
      EmulatorChecksum[Loop]:= '';

      emuROMsFolders[Loop]:= nil;
      imgZipContents[Loop]:= nil;
      imgZipContentsFullPath[Loop]:= nil;
    end;
    for Loop:=1 to MaxArcadeSystems do
    begin
      for Loop2:=0 to 11 do
          imgFolderZipFile[Loop, Loop2]:= '';
    end;
  except
    GenerateMessage('Error', 'Could not define initial values to emulator variables', 2);
  end;
  EmulatorRunOnce:= True;
end;

function CompareColumnsValue(GameItem1, GameItem2: pGameInfo; ColumnID: Integer): Integer;
var
  prevID: Integer;
begin
  case ColumnID of
    00: Result:= CompareText(GameItem1.eDescription, GameItem2.eDescription);
    01: Result:= CompareText(GameItem1.eYear, GameItem2.eYear);
    02: Result:= CompareText(GameItem1.eManufacturer, GameItem2.eManufacturer);
    03: Result:= CompareText(aAudioChannels[GameItem1.eAudioChannels], aAudioChannels[GameItem2.eAudioChannels]);
    04: Result:= CompareText(aAudioSamples[GameItem1.eAudioSamples], aAudioSamples[GameItem2.eAudioSamples]);
    05: Result:= CompareText(IntToStr(GameItem1.eNumberScreens), IntToStr(GameItem2.eNumberScreens));

    06: Result:= CompareText(aScreenType[GameItem1.eScreenType1], aScreenType[GameItem2.eScreenType1]);
    07: Result:= CompareText(FormMain.MountOrientation(GameItem1.eScreenRotation1), FormMain.MountOrientation(GameItem2.eScreenRotation1));
    08: Result:= CompareText(FormMain.MountResolution(GameItem1.eResolutionWidth1, GameItem1.eResolutionHeight1, GameItem1.eScreenRotation1),
                             FormMain.MountResolution(GameItem2.eResolutionWidth1, GameItem2.eResolutionHeight1, GameItem2.eScreenRotation1));
    09: Result:= CompareText(GameItem1.eRefreshRate1, GameItem2.eRefreshRate1);


    10: Result:= CompareText(aScreenType[GameItem1.eScreenType2], aScreenType[GameItem2.eScreenType2]);
    11: Result:= CompareText(FormMain.MountOrientation(GameItem1.eScreenRotation2), FormMain.MountOrientation(GameItem2.eScreenRotation2));
    12: Result:= CompareText(FormMain.MountResolution(GameItem1.eResolutionWidth2, GameItem1.eResolutionHeight2, GameItem1.eScreenRotation2),
                             FormMain.MountResolution(GameItem2.eResolutionWidth2, GameItem2.eResolutionHeight2, GameItem2.eScreenRotation2));
    13: Result:= CompareText(GameItem1.eRefreshRate2, GameItem2.eRefreshRate2);

    14: Result:= CompareText(aScreenType[GameItem1.eScreenType3], aScreenType[GameItem2.eScreenType3]);
    15: Result:= CompareText(FormMain.MountOrientation(GameItem1.eScreenRotation3), FormMain.MountOrientation(GameItem2.eScreenRotation3));
    16: Result:= CompareText(FormMain.MountResolution(GameItem1.eResolutionWidth3, GameItem1.eResolutionHeight3, GameItem1.eScreenRotation3),
                             FormMain.MountResolution(GameItem2.eResolutionWidth3, GameItem2.eResolutionHeight3, GameItem2.eScreenRotation3));
    17: Result:= CompareText(GameItem1.eRefreshRate3, GameItem2.eRefreshRate3);

    18: Result:= CompareText(aScreenType[GameItem1.eScreenType4], aScreenType[GameItem2.eScreenType4]);
    19: Result:= CompareText(FormMain.MountOrientation(GameItem1.eScreenRotation4), FormMain.MountOrientation(GameItem2.eScreenRotation4));
    20: Result:= CompareText(FormMain.MountResolution(GameItem1.eResolutionWidth4, GameItem1.eResolutionHeight4, GameItem1.eScreenRotation4),
                             FormMain.MountResolution(GameItem2.eResolutionWidth4, GameItem2.eResolutionHeight4, GameItem2.eScreenRotation4));
    21: Result:= CompareText(GameItem1.eRefreshRate4, GameItem2.eRefreshRate4);

    22: Result:= CompareText(aStatus[GameItem1.eDriverStatus], aStatus[GameItem2.eDriverStatus]);
    23: Result:= CompareText(aStatus[GameItem1.eEmulationStatus], aStatus[GameItem2.eEmulationStatus]);
    24: Result:= CompareText(aStatus[GameItem1.eColorStatus], aStatus[GameItem2.eColorStatus]);
    25: Result:= CompareText(aStatus[GameItem1.eSoundStatus], aStatus[GameItem2.eSoundStatus]);
    26: Result:= CompareText(aStatus[GameItem1.eGraphicStatus], aStatus[GameItem2.eGraphicStatus]);
    27: Result:= CompareText(aStatus[GameItem1.eCocktailStatus], aStatus[GameItem2.eCocktailStatus]);
    28: Result:= CompareText(aStatus[GameItem1.eProtectionStatus], aStatus[GameItem2.eProtectionStatus]);

    29: Result:= CompareText(GameItem1.eCategory, GameItem2.eCategory);
    30: Result:= CompareText(GameItem1.eVersionAdded, GameItem2.eVersionAdded);
    31: Result:= CompareText(GameItem1.eName, GameItem2.eName);
    32: Result:= CompareText(GameItem1.eClone, GameItem2.eClone);
    33: Result:= CompareText(GameItem1.eDriverName, GameItem2.eDriverName);
    34: Result:= CompareText(GameItem1.eMerged, GameItem2.eMerged);
    35: Result:= CompareText(GameItem1.ePlayTime, GameItem2.ePlayTime);
    36: Result:= CompareText(IntToStr(GameItem1.ePlayed), IntToStr(GameItem2.ePlayed));
    37: Result:= CompareText(GameItem1.eNumberPlayers, GameItem2.eNumberPlayers);
    38: Result:= CompareText(aControlType[GameItem1.eControlType, 0], aControlType[GameItem2.eControlType, 0]);
    39: Result:= CompareText(aSaveState[GameItem1.eSaveState], aSaveState[GameItem2.eSaveState]);
    50: begin
          FormMain.GetSystemID(GameItem1.eROMIdentification);
          prevID:= FormMain.SystemID_Number;
          FormMain.GetSystemID(GameItem2.eROMIdentification);

          if prevID = FormMain.SystemID_Number then
             Result:= 0
          else
          if prevID > FormMain.SystemID_Number then
             Result:= 1
          else
             Result:= -1;
        end;
  end;
  if (ColumnID > 0) and (Result = 0) then
     Result:= CompareText(GameItem1.eDescription, GameItem2.eDescription);
end;

// old sort routine
procedure TFormMain.SortColumn(ForceAscending: Boolean);
begin
  with GamesTreeView.Header, GamesTreeView do
  begin
    if SortColumn > NoColumn then
      Columns[SortColumn].Options:= Columns[SortColumn].Options + [coParentColor];
    if (SortColumn = NoColumn) or (SortColumn <> ColumnsSort[ButtonGameFilterArcade.Tag, 0]) then
       SortColumn:= ColumnsSort[ButtonGameFilterArcade.Tag, 0];
    case ForceAscending of
      True: SortDirection:= sdAscending;
      False:
        begin
          case Ord(ColumnsSort[ButtonGameFilterArcade.Tag, 1]) of
            0: SortDirection:= sdAscending;
            1: SortDirection:= sdDescending;
          end;
        end;
    end;
    if not FormPreferences.GamesBackgroundImageEnable.Checked then
       Columns[SortColumn].Color:= FormPreferences.SortedColumnColor.Selected; // $F7F7F7;
    ColumnsSort[ButtonGameFilterArcade.Tag, 0]:= SortColumn;
    ColumnsSort[ButtonGameFilterArcade.Tag, 1]:= Ord(SortDirection = sdDescending);
    SortTree(SortColumn, SortDirection, False);
    ScrollIntoView(SelectedNode, True);
  end;
end;

function TFormMain.PopulateROMDataLine: String;
begin
  Result:= Format('%.2u', [mROMIdentification])+'¬'+
           IntToStr(mMediaType)+'¬'+
           mDescription+'¬'+
           mYear+'¬'+
           mManufacturer+'¬'+
           IntToStr(mAudioChannels)+'¬'+
           IntToStr(mAudioSamples)+'¬'+
           mAudioSampleName+'¬'+
           mControls+'¬'+
           IntToStr(mScreenType1)+'¬'+
           IntToStr(mScreenRotation1)+'¬'+
           IntToStr(mResolutionWidth1)+'¬'+
           IntToStr(mResolutionHeight1)+'¬'+
           mRefreshRate1+'¬'+
           IntToStr(mScreenType2)+'¬'+
           IntToStr(mScreenRotation2)+'¬'+
           IntToStr(mResolutionWidth2)+'¬'+
           IntToStr(mResolutionHeight2)+'¬'+
           mRefreshRate2+'¬'+
           IntToStr(mScreenType3)+'¬'+
           IntToStr(mScreenRotation3)+'¬'+
           IntToStr(mResolutionWidth3)+'¬'+
           IntToStr(mResolutionHeight3)+'¬'+
           mRefreshRate3+'¬'+
           IntToStr(mScreenType4)+'¬'+
           IntToStr(mScreenRotation4)+'¬'+
           IntToStr(mResolutionWidth4)+'¬'+
           IntToStr(mResolutionHeight4)+'¬'+
           mRefreshRate4+'¬'+
           IntToStr(mDriverStatus)+'¬'+
           IntToStr(mEmulationStatus)+'¬'+
           IntToStr(mColorStatus)+'¬'+
           IntToStr(mSoundStatus)+'¬'+
           IntToStr(mGraphicStatus)+'¬'+
           IntToStr(mCocktailStatus)+'¬'+
           IntToStr(mProtectionStatus)+'¬'+
           mBiosName+'¬'+
           mClone+'¬'+
           mDriverName+'¬'+
           mMerged+'¬'+
           mGameSize+'¬'+
           IntToStr(mSaveState)+'¬'+
           mNumberPlayers+';';
end;

function TFormMain.SearchString(const SubString, StringLine: String): Boolean;
var
  Position: Integer;
begin
  Position:= Pos(SubString, StringLine);
  Result:= ((Position > 0) and (Copy(StringLine, Position, Length(SubString)) = SubString));
end;

procedure TFormMain.UpdateMAMEsnapDir(dirString: String; SystemID: ShortInt);
var
  MAMEIniFile: THashedStringList;
  IniFile, finalDir: String;
  Loop: Integer;
begin
  finalDir:= dirString;
  if (Pos('.zip', LowerCase(dirString)) <> 0) then
     finalDir:= ExtractFilePath(finalDir);

  if (not FileExists(EmulatorFile[SystemID])) or (EmulatorFile[SystemID] = '') then
     Exit;
  iniFile:= GetMAMEIniFileName(EmulatorFile[SystemID], SystemID);
  if not FileExists(iniFile) then
     Exit;
  if CheckReadOnly(iniFile) then
     Exit;

  MAMEIniFile:= THashedStringList.Create;
  MAMEIniFile.LoadFromFile(iniFile);
  for Loop:=0 to MAMEIniFile.Count -1 do
  begin
    if Copy(MAMEIniFile[Loop], 1, 19) = 'snapshot_directory ' then
       begin
         MAMEIniFile.Strings[Loop]:= 'snapshot_directory      '+ExcludeTrailingPathDelimiter(finalDir);
         MAMEIniFile.SaveToFile(iniFile);
         Break;
       end;
  end;
  FreeAndNil(MAMEIniFile);
end;

procedure TFormMain.DialogOpenFile(FilterType: ShortInt; const DialogTitle: String; EditHolder: TEdit; MultipleFiles, GraphicImage: Boolean; const DefaultDirectory: String = '');
var
  Continue: Boolean;
  SelectedFile: String;
begin
  case GraphicImage of
    True:
      begin
        OpenImageDialog.FilterIndex:= FilterType;
        OpenImageDialog.Title:= DialogTitle;
      end;
    False:
      begin
        case FilterType of
           0: OpenDialog.Filter:= 'Executable files (*.exe)|*.exe';
           1: OpenDialog.Filter:= 'Input files (*.inp)|*.inp';
           2: OpenDialog.Filter:= 'Executable files (*.exe)|*.exe|Batch files (*.bat)|*.bat|All files (*.*)|*.*';
           3: OpenDialog.Filter:= 'Data files (*.dat; *.el)|*.dat; *.el';
           4: OpenDialog.Filter:= 'JPEG image file (*.jpg; *.jpeg)|*.jpg; *.jpeg';
           5: OpenDialog.Filter:= 'PNG image file (*.png)|*.png';
           6: OpenDialog.Filter:= 'Initialization files (*.ini)|*.ini';
           7: OpenDialog.Filter:= 'Zip files (*.zip)|*.zip';
           8: OpenDialog.Filter:= 'All image formats (*.png;*.gif;*.jpg;*.bmp)|*.png;*.gif;*.jpg;*.bmp';
           9: OpenDialog.Filter:= 'ZiNc files (*.znc)|*.znc';
          10: OpenDialog.Filter:= 'Config files (*.cfg)|*.cfg';
          11: OpenDialog.Filter:= 'All files (*.*)|*.*';
          12: OpenDialog.Filter:= 'Batch files (*.bat)|*.bat';
        end;
        OpenDialog.Title:= DialogTitle;
      end;
  end;

  if DefaultDirectory <> '' then
     begin
       case GraphicImage of
         True : OpenImageDialog.InitialDir:=  DefaultDirectory;
         False: OpenDialog.InitialDir:=  DefaultDirectory;
       end;
     end;

  case GraphicImage of
    True : Continue:= OpenImageDialog.Execute;
    False: Continue:= OpenDialog.Execute;
  end;

  if Continue then
     begin
       case GraphicImage of
         True : SelectedFile:= OpenImageDialog.FileName;
         False: SelectedFile:= OpenDialog.FileName;
       end;

       if EditHolder <> nil then
          begin
            case MultipleFiles of
              True:
                begin
                  if EditHolder.Text <> '' then
                     EditHolder.Text:= EditHolder.Text+';'+SelectedFile
                  else
                     EditHolder.Text:= SelectedFile;
                end;
              False:
                begin
                  EditHolder.Text:= SelectedFile;
                end;
            end;
          end;
     end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.DialogSelectFolder(EditHolder: TEdit; MultipleFolders: Boolean);
var
  DialogText, Value: String;
begin
  DialogText:= 'Select a folder for ';
  if EditHolder.Name = 'FolderROMsHardDiskImages' then
     DialogText:= DialogText+'ROMs / Hard Disk Images'
  else
  if EditHolder.Name = 'FolderSamples' then
     DialogText:= DialogText+'Samples'
  else
  if EditHolder.Name = 'FolderIniFiles' then
     DialogText:= DialogText+'games .ini files'
  else
  if EditHolder.Name = 'FolderGamesConfigurations' then
     DialogText:= DialogText+'Games Configuration'
  else
  if EditHolder.Name = 'FolderNVRAM' then
     DialogText:= DialogText+'NVRAM'
  else
  if EditHolder.Name = 'FolderMemoryCards' then
     DialogText:= DialogText+'Memory Cards'
  else
  if EditHolder.Name = 'FolderInputDeviceLogs' then
     DialogText:= DialogText+'Input Device Logs'
  else
  if EditHolder.Name = 'FolderSaveStates' then
     DialogText:= DialogText+'Save States'
  else
  if EditHolder.Name = 'FolderArtworks' then
     DialogText:= DialogText+'Artworks'
  else
  if EditHolder.Name = 'FolderGameSnapshots' then
     DialogText:= DialogText+'Game Snapshots'
  else
  if EditHolder.Name = 'FolderDiff' then
     DialogText:= DialogText+'Hard Drive Image Difference Files'
  else
  if EditHolder.Name = 'FolderControllerDefinitions' then
     DialogText:= DialogText+'Controller Definition Files'
  else
  if EditHolder.Name = 'FolderDebuggerComments' then
     DialogText:= DialogText+'Debug Comment Files'
  else
  if EditHolder.Name = 'FolderIPS' then
     DialogText:= DialogText+'IPS Patch Files (MAME Plus!)'
  else
  if EditHolder.Name = 'FolderLanguages' then
     DialogText:= DialogText+'Language Files (MAME Plus!)'
  else
  if EditHolder.Name = 'ZipTitleSnapshots' then
     DialogText:= DialogText+FormPreferences.LabelZipTitleSnapshots.Caption
  else
  if EditHolder.Name = 'ZipGameSnapshots' then
     DialogText:= DialogText+FormPreferences.LabelZipGameSnapshots.Caption
  else
  if EditHolder.Name = 'ZipMarquees' then
     DialogText:= DialogText+FormPreferences.LabelZipMarquees.Caption
  else
  if EditHolder.Name = 'ZipFlyers' then
     DialogText:= DialogText+FormPreferences.LabelZipFlyers.Caption
  else
  if EditHolder.Name = 'ZipCabinets' then
     DialogText:= DialogText+FormPreferences.LabelZipCabinets.Caption
  else
  if EditHolder.Name = 'ZipControlPanels' then
     DialogText:= DialogText+FormPreferences.LabelZipControlPanels.Caption
  else
  if EditHolder.Name = 'ZipControlPanelLayouts' then
     DialogText:= DialogText+FormPreferences.LabelZipControlPanelLayouts.Caption
  else
  if EditHolder.Name = 'ZipSelect' then
     DialogText:= DialogText+FormPreferences.LabelZipSelect.Caption
  else
  if EditHolder.Name = 'ZipVersus' then
     DialogText:= DialogText+FormPreferences.LabelZipVersus.Caption
  else
  if EditHolder.Name = 'ZipWallpapers' then
     DialogText:= DialogText+FormPreferences.LabelZipWallpapers.Caption
  else
  if EditHolder.Name = 'ZipHardware' then
     DialogText:= DialogText+FormPreferences.LabelZipHardware.Caption
  else
  if EditHolder.Name = 'ZipCustomImage' then
     DialogText:= DialogText+FormPreferences.LabelZipCustomImage.Caption
  else
  if EditHolder.Name = 'ZipIcons' then
     DialogText:= DialogText+'Games Icons'
  else
  if EditHolder.Name = 'FolderGamesFAQ' then
     DialogText:= DialogText+'Games F.A.Q.'
  else
  if EditHolder.Name = 'DefaultGameIconsFolder' then
     DialogText:= DialogText+'Default Icons'
  else
  if EditHolder.Name = 'FrontendIconsFolder' then
     DialogText:= DialogText+'Frontend Icons Folder'
  else
  if EditHolder.Name = 'AudioFolder' then
     DialogText:= DialogText+
                  GetSystemIniSection(FormPreferences.AudioSystemSelector.Tag)+
                  ' Audio Samples';

  if SelectDirectory(DialogText, '', Value) then
     begin
       Value:= ExcludeTrailingPathDelimiter(Value);
       case MultipleFolders of
         True:
           begin
             if EditHolder.Text <> '' then
                EditHolder.Text:= EditHolder.Text+';' + Value
             else
                EditHolder.Text:= Value;
           end;
         False: EditHolder.Text:= Value;
       end;
     end;
end;

procedure TFormMain.DialogSelectMultiFolders(ListHolder: TListBox; SubFolders: Boolean; HashedList: THashedStringList = nil);
var
  DialogText, Value: String;
  SubFoldersList: THashedStringList;
begin
  DialogText:= 'Select a folder for ';
  if ListHolder.Name = 'FolderROMsHardDiskImages' then
     DialogText:= DialogText+'ROMs / Hard Disk Images'
  else
  if ListHolder.Name = 'ConsoleFoldersList' then
     DialogText:= DialogText+'Console Games';

  if SelectDirectory(DialogText, '', Value) then
     begin
       Value:= ExcludeTrailingPathDelimiter(Value);
       case SubFolders of
         True:
           begin
             SubFoldersList:= THashedStringList.Create;
             GetFoldersList(Value, SubFoldersList, True, True);
             if SubFoldersList.Count > 0 then
                begin
                  ListHolder.Items.AddStrings(SubFoldersList);
                  if Assigned(HashedList) then
                     HashedList.AddStrings(SubFoldersList);
                end;
             FreeAndNil(SubFoldersList);
           end;
         False:
           begin
             ListHolder.Items.Add(Value);
             if Assigned(HashedList) then
                HashedList.Add(Value);
           end;
       end;
     end;
end;

// New Full Screen mode function
procedure TFormMain.WMSystemCommand(var Msg: TWMSysCommand);
begin
  case MenuViewFullScreen.Checked of
    True:
      begin
        if (Msg.cmdType = SC_MAXIMIZE) or (Msg.cmdType = SC_MINIMIZE) then
           Msg.Result:= -1
        else
        if Msg.cmdType = SC_CLOSE then
           // do nothing... maybe delete this IF ?
      end;
    False: inherited;
  end;
end;

function TFormMain.IsThemesEnabled: Boolean;
begin
  Result:= False;
  with ThemeServices do
  begin
    case ThemesAvailable of
      True : Result:= ThemesEnabled;
      False: Result:= False;
    end;
  end;
  if Result then
     Result:= FileExists(FrontendPath+ShortToLongFileName(Application.ExeName)+'.manifest');
end;

function TFormMain.CheckReadOnly(const FileString: String): Boolean;
var
  FileAttributes: Word;
begin
  Result:= FileExists(FileString);
  if Result then
     begin
       FileAttributes:= FileGetAttr(FileString);
       Result:= (FileAttributes and faReadOnly) = faReadOnly;
       //Result:= (FileAttributes and faArchive) = faArchive;
       //Result:= (FileAttributes and faSysFile) = faSysFile;
       //Result:= (FileAttributes and faHidden) = faHidden;
     end;
  if Result then
     begin
       if FormPreferences.ReadOnlyMessage.Checked then
          GenerateMessage('Warning', 'Could not save "'+FileString+'". '+
                          'File is marked as read-only!', 2);
     end;
end;

function TFormMain.IsSystemEntry(SystemName: String): Boolean;
begin
  Result:= (SystemName = 'system_node');
end;

function TFormMain.CheckSelected(TreeViewHolder: TVirtualStringTree): Boolean;
begin
  Result:= (TreeViewHolder.VisibleCount > 0) and
           (TreeViewHolder.SelectedCount > 0);
end;

function TFormMain.CheckTotal(TreeViewHolder: TVirtualStringTree): Boolean;
begin
  Result:= TreeViewHolder.TotalCount > 0;
end;

function TFormMain.CheckTotalVisible(TreeViewHolder: TVirtualStringTree): Boolean;
begin
  Result:= TreeViewHolder.VisibleCount > 0;
end;

procedure TFormMain.FocusGamesList;
begin
  GamesTreeView.SetFocus;
end;

function TFormMain.SetLockedGamesList(Mode: Boolean): Boolean;
var
  Loop: Integer;
begin
  case Mode of
    True:
      begin
        Result:= ValidateFile(FrontendPath+'ini_files\parental_lock.ini');
        if Result then
           begin
             ParentalLockGamesList:= THashedStringList.Create;
             ParentalLockGamesList.LoadFromFile(FrontendPath+'ini_files\parental_lock.ini');
             Result:= (ParentalLockGamesList.Count > 1);
             if Result then
                begin
                  ParentalLockGamesList.BeginUpdate;
                  for Loop:=0 to ParentalLockGamesList.Count -1 do
                      ParentalLockGamesList[Loop]:= DecryptData(ParentalLockGamesList[Loop]);
                  ParentalLockGamesList.EndUpdate;
                  if ParentalLockGamesList.Names[0] = 'password' then
                     ParentalLockPasswordString:= ParentalLockGamesList.ValueFromIndex[0]
                  else
                     begin
                       ParentalLockPasswordString:= '';
                       GenerateMessage('Error', 'Could not extract password from "'+
                                       FrontendPath+'ini_files\parental_lock.ini". Password not found!', 2);
                     end;
                end;
           end;
      end;
    False: FreeAndNil(ParentalLockGamesList);
  end;
end;

procedure TFormMain.MinimizeToTray;
begin
  if Assigned(FormRandomGamePreviewPanel) and FormRandomGamePreviewPanel.Visible then
     FormRandomGamePreviewPanel.Visible:= False;

  if Assigned(FormTextViewer) and FormTextViewer.Visible then
     FormTextViewer.Visible:= False;

  Application.MainForm.Visible:= False;

  //Application.Minimize;

  // ..and hide the taskbar button of the application
  CoolTrayIcon.HideTaskbarIcon;
  CoolTrayIcon.IconVisible:= True;
end;

procedure TFormMain.RestoreFromTray;
begin
  Application.MainForm.Visible:= True;

  if Assigned(FormRandomGamePreviewPanel) and (not FormRandomGamePreviewPanel.Visible) then
     FormRandomGamePreviewPanel.Visible:= True;

  if Assigned(FormTextViewer) and (not FormTextViewer.Visible) then
     FormTextViewer.Visible:= True;

  CoolTrayIcon.ShowTaskbarIcon;
  CoolTrayIcon.IconVisible:= False;
  if Application.MainForm.WindowState = wsMinimized then
     Application.Restore;
  // Bring the main form (or its modal dialog) to the foreground
  SetForegroundWindow(Application.Handle);
end;

function TFormMain.RunProcess(AppPath: String; MustWait: Boolean=False;
  Visibility: Word=SW_SHOWNORMAL; RunningGame: Boolean=True): DWORD;
var
  SI: TStartupInfo;
  PI: TProcessInformation;
  Proc: THandle;
  zFileName: array[0..255] of Char;
  MillisecondsCount: Cardinal;
  ErrorMsg: DWORD;
begin
  if Length(AppPath) > 254 then
     begin
       GenerateMessage('Error', Format('The command line has more than 254 characters - [%u]', [Length(AppPath)]), 2);
       Exit;
     end;

  FillChar(SI, SizeOf(SI), 0);
  SI.cb:= SizeOf(SI);
  SI.dwFlags:= StartF_UseShowWindow;
  SI.wShowWindow:= Visibility;
  StrPCopy(zFileName, AppPath);

  if not CreateProcess(nil, zFileName,
     nil, nil, False, Create_New_Console+Normal_Priority_Class, nil, nil, SI, PI) then
     begin
       ErrorMsg:= GetLastError;
       GenerateMessage('Execution Failed', Format('Failed to excecute'+#13#10+'%s'+#13#10+#13#10+
                       'Error Code %d: '+SysErrorMessage(ErrorMsg), [AppPath, GetLastError]), 2);
     end;

  Proc:= PI.hProcess;
  CloseHandle(PI.hThread);

  if MustWait then
     begin
       case MenuRandomGamePreview.Checked of
         True:
           begin
             if RunningGame then
                begin
                  FormRandomGamePreviewPanel.Hide;
                  MillisecondsCount:= 0;
                  GetExitCodeProcess(Proc, Result);
                  while (MillisecondsCount < FormPreferences.GamePreviewRunningTime.Position) do
                  begin
                    Application.ProcessMessages;
                    if WaitForSingleObject(Proc, 5000) <> Wait_Failed then
                       GetExitCodeProcess(Proc, Result);
                    Inc(MillisecondsCount, 5000);
                  end;
                end;
           end;
         False:
           begin
             GetExitCodeProcess(Proc, Result);
              while (Result = STILL_ACTIVE) do
              begin
                Application.ProcessMessages;
                if WaitForSingleObject(Proc, 10000) <> Wait_Failed then
                   GetExitCodeProcess(Proc, Result);
              end;
           end;
       end;
     end;
  if RunningGame and MenuRandomGamePreview.Checked then
     TerminateProcess(Proc, Result);
  CloseHandle(Proc);

{---PARAMETERS------------------------------------------------------------------
AppPath: The full path and Application Name to run ie. c:winnt notepad.exe

MustWait: true if the code must be paused until the termination of the launched
  Application. false if the code must run directly after launching the app.

AppParams: Commandline params to send to the app.

Visibility:
Can have any of the following values:
  Value Meaning
  SW_HIDE Hides the window and activates another window.
  SW_MAXIMIZE Maximizes the specified window.
  SW_MINIMIZE Minimizes the specified window and activates the next top-level
    window in the Z order.
  SW_RESTORE Activates and displays the window. If the window is minimized or
    maximized, Windows restores it to its original size and position. An
    application should specify this flag when restoring a minimized window.
  SW_SHOW Activates the window and displays it in its current size and position.
  SW_SHOWDEFAULT Sets the show state based on the SW_ flag specified in the
    STARTUPINFO structure passed to the CreateProcess function by the program
    that started the application.
  SW_SHOWMAXIMIZED Activates the window and displays it as a maximized window.
  SW_SHOWMINIMIZED Activates the window and displays it as a minimized window.
  SW_SHOWMINNOACTIVE Displays the window as a minimized window. The active
    window remains active.
  SW_SHOWNA Displays the window in its current state. The active window remains
    active.
  SW_SHOWNOACTIVATE Displays a window in its most recent size and position.
    The active window remains active.
  SW_SHOWNORMAL Activates and displays a window. If the window is minimized or
    maximized, Windows restores it to its original size and position. An
    application should specify this flag when displaying the window for the
    first time.
-------------------------------------------------------------------------------}
end;

procedure TFormMain.ClearEmulatorVariables(SystemID: Integer);
begin
  EmulatorFile[SystemID]:= '';
  EmulatorVersion[SystemID]:= '';
  EmulatorChecksum[SystemID]:= '';
end;

function TFormMain.GetEmulatorVersion(SystemID: Integer; const FileName: String; out StoreResultIn: String): Boolean;
var
  CommandLine, VersionDescription, tempFile: String;
  BatchFile: THashedStringList;
  Continue, IsStatusOpened: Boolean;
begin
  isStatusOpened:= FormStatus.Visible;
  SetCurrentDir(FrontendPath);

  Continue:= VerifyTempDirectory;
  if Continue then
     begin
       case SystemID of
         1: tempFile:= FrontendPath+'temp\MAMEVersion.tmp';
         2: tempFile:= FrontendPath+'temp\ZiNcVersion.tmp';
         4: tempFile:= FrontendPath+'temp\AGEMAMEVersion.tmp';
         5: tempFile:= FrontendPath+'temp\PinMAMEVersion.tmp';
         6: tempFile:= FrontendPath+'temp\HazeMDVersion.tmp';
       end;
       case SystemID of
         1, 4, 5, 6: CommandLine:= SystemStr+FileName+SystemStr+' -help > '+SystemStr+tempFile+SystemStr;
         2: CommandLine:= SystemStr+FileName+SystemStr+' --version > '+SystemStr+tempFile+SystemStr;
       end;
     end;

  if Continue then
     begin
       RunMAMEInitialize(SystemID);
       if SystemID <> 3 then
          begin
            case Win32Platform of
              0,1: RunProcess('command.com /c '+CommandLine, True, Get_DOSBox_Status(False), False); //Win9x
              2  : RunProcess('cmd.exe /c '+SystemStr+CommandLine+SystemStr, True, Get_DOSBox_Status(False), False); // WinXP and Vista
            end;
          end;

       if SystemID = 3 then
          begin
            if EmulatorVersion[3] = '' then
               VersionDescription:= Daphne_VersionInfo
            else
               VersionDescription:= EmulatorVersion[3];
          end
       else
       if FileExists(tempFile) then
          begin
            BatchFile:= THashedStringList.Create;
            try
              BatchFile.LoadFromFile(tempFile);
              if BatchFile.Count > 0 then
                 begin
                   case SystemID of
                     1, 4, 5, 6:
                       begin
                         VersionDescription:= BatchFile[0];
                         VersionDescription:= Copy(VersionDescription, 1, Pos(' -', VersionDescription));
                         VersionDescription:= Trim(VersionDescription);
                       end;
                     2: VersionDescription:= BatchFile[0];
                   end;
                 end;
            finally
            end;
            FreeAndNil(BatchFile);
            DeleteFile(tempFile);
            Application.ProcessMessages;
          end;
     end;

  if VersionDescription = '' then
     begin
       if isStatusOpened then
          FormStatus.Visible:= False;
       StoreResultIn:=
       InputBoxEL(GetEmuFullDescription(SystemID)+#13#10+'Unable to extract the version info.',
                  'Enter a description', EmulatorVersion[SystemID]);
     end
  else
     StoreResultIn:= VersionDescription;
  Result:= VersionDescription <> '';
  if isStatusOpened and Result then
     FormStatus.Visible:= True;
end;

procedure TFormMain.SetSelectedColorBox(ColorBoxHolder: TColorBox; Color: TColor);
begin
  ColorBoxHolder.Selected:= Color;
  ColorBoxHolder.OnSelect(Self);
end;

procedure TFormMain.FixEmptyValue(TextHolder: TEdit; StringValue: String);
begin
  if TextHolder.Text = '' then
     TextHolder.Text:= StringValue;
end;

function TFormMain.GetBatchFileFieldIndex(ParameterIndex: String): String;
begin
  Result:= '-1';
  case StrToInt(ParameterIndex) of
    0: Result:= '0'; // description
    1: Result:= '6'; // screen type
    2: Result:= '7'; // orientation
    3: Result:= '8'; // resolution
    4: Result:= '31'; // name
    5: Result:= '32'; // clone of
    6: Result:= '33'; // driver name
    7: Result:= '39'; // control type
  end;
end;

function TFormMain.ReadCustomCommandLine(sFileName: String; romID: Integer; RunningGame: Boolean = False): String;
var
  CommandLineFile: THashedStringList;
  sEmulatorBatchFile, sParametersPrefix, sParameters, sParametersSuffix, sQuotes, sAdditionalParameters, Folder, System: String;
  PrefixList, ParametersList, SuffixList, QuotesList: TStringList;
  Loop, sIndex, PrefixSendLeadingSpace: Integer;

  function ExtractFieldsList(ParamStr: String; StringListHolder: TStringList): Boolean;
  var
    LoopFList: Integer;
    TempField: String;
  begin
    Result:= True;
    TempField:= '';
    if (ParamStr = '') or
       (not Assigned(StringListHolder)) then
       begin
         Result:= False;
         Exit;
       end;
    for LoopFList:=1 to Length(ParamStr) do
    begin
      if (ParamStr[LoopFList] = '¬') or (ParamStr[LoopFList] = ';') then
         begin
           StringListHolder.Add(TempField);
           TempField:= '';
         end
      else
         TempField:= TempField+ParamStr[LoopFList];
    end;
  end;

begin
  Result:= '';
  Folder:= 'ini_files\cmdline\';
  System:= GetSystemFolderName(romID)+'\';
  if ValidateFile(FrontendPath+Folder+System+sFileName+'.ini') then
     begin
       CommandLineFile:= THashedStringList.Create;
       CommandLineFile.LoadFromFile(FrontendPath+Folder+System+sFileName+'.ini');
       sEmulatorBatchFile:= CommandLineFile.Values['FileName'];
       sParametersPrefix:= CommandLineFile.Values['Prefix'];
       PrefixSendLeadingSpace:= StrToInt(CommandLineFile.Values['PrefixSendLeadingSpace']);
       sParameters:= CommandLineFile.Values['Parameters'];
       sParametersSuffix:= CommandLineFile.Values['Suffix'];
       sQuotes:= CommandLineFile.Values['Quotes'];
       sAdditionalParameters:= CommandLineFile.Values['AdditionalParameters'];
       FreeAndNil(CommandLineFile);
       if sEmulatorBatchFile = '' then
          begin
            GenerateMessage('Error', 'Filename is empty, cannot execute custom command line.'+
                            'Aborting...', 2);
            Exit;
          end;
       PrefixList:= TStringList.Create;
       ParametersList:= TStringList.Create;
       SuffixList:= TStringList.Create;
       QuotesList:= TStringList.Create;
       ExtractFieldsList(sParametersPrefix, PrefixList);
       ExtractFieldsList(sParameters, ParametersList);
       ExtractFieldsList(sParametersSuffix, SuffixList);
       ExtractFieldsList(sQuotes, QuotesList);

       if Assigned(PrefixList) and Assigned(ParametersList) and
          Assigned(SuffixList) and Assigned(QuotesList) then
          begin
            for Loop:=0 to ParametersList.Count-1 do
            begin
              case RunningGame of
                False:
                  begin
                    FormCustomCommandLine.Parameters.Items.BeginUpdate;
                    sIndex:= StrToInt(ParametersList[Loop]);
                    if sIndex > FormCustomCommandLine.FieldToAdd.ItemsEx.Count then
                       begin
                         GenerateMessage('Error', Format('Parameter #%u.'+#13#10+'Index "%u" is invalid! '+
                                         'Will replace it by "Name" field.', [Loop+1, sIndex]), 2);
                         sIndex:= 4;
                       end;
                    with FormCustomCommandLine.Parameters.Items.Add do
                    begin
                      ImageIndex:= FormCustomCommandLine.FieldToAdd.ItemsEx[sIndex].ImageIndex;
                      StateIndex:= sIndex;
                      Caption:= PrefixList[Loop];
                      SubItems.Add(FormCustomCommandLine.FieldToAdd.ItemsEx[sIndex].Caption);
                      SubItems.Add(SuffixList[Loop]);
                      case StrToInt(QuotesList[Loop]) of
                        0: SubItems.Add('No');
                        1: SubItems.Add('Yes');
                      end;
                    end;
                    FormCustomCommandLine.Parameters.Items.EndUpdate;
                  end;
                True:
                  begin
                    sParametersPrefix:= PrefixList[Loop];
                    sParameters:= GetBatchFileFieldIndex(ParametersList[Loop]);
                    sParametersSuffix:= SuffixList[Loop];
                    case StrToInt(QuotesList[Loop]) of
                      0: sQuotes:= '';
                      1: sQuotes:= '"';
                    end;
                    if (Result <> '') and Boolean(PrefixSendLeadingSpace) then
                       sParametersPrefix:= ' '+sParametersPrefix;
                    case StrToInt(sParameters) of
                      00: Result:= Result+sParametersPrefix+sQuotes+GameInfoData.eDescription+sQuotes+sParametersSuffix;
                      06: Result:= Result+sParametersPrefix+sQuotes+aScreenType[GameInfoData.eScreenType1]+sQuotes+sParametersSuffix;
                      07: Result:= Result+sParametersPrefix+sQuotes+MountOrientation(GameInfoData.eScreenRotation1)+sQuotes+sParametersSuffix;
                      08: Result:= Result+sParametersPrefix+sQuotes+MountResolution(GameInfoData.eResolutionWidth1, GameInfoData.eResolutionHeight1, GameInfoData.eScreenRotation1)+sQuotes+sParametersSuffix;
                      31: Result:= Result+sParametersPrefix+sQuotes+GameInfoData.eName+sQuotes+sParametersSuffix;
                      32: Result:= Result+sParametersPrefix+sQuotes+GameInfoData.eClone+sQuotes+sParametersSuffix;
                      33: Result:= Result+sParametersPrefix+sQuotes+GameInfoData.eDriverName+sQuotes+sParametersSuffix;
                      39: Result:= Result+sParametersPrefix+sQuotes+aControlType[GameInfoData.eControlType, 0]+sQuotes+sParametersSuffix;
                    end;
                  end;
              end;
            end;
          end;
       case RunningGame of
         True:
           begin
             if Result <> '' then
                begin
                  Result:= WinQuotesStr+sEmulatorBatchFile+WinQuotesStr+' '+Result;
                  if sAdditionalParameters <> '' then
                     Result:= Result+' '+sAdditionalParameters;
                end
             else
                Result:= WinQuotesStr+sEmulatorBatchFile+WinQuotesStr;
           end;
         False:
           begin
             Result:='file_found';
             FormCustomCommandLine.EmulatorBatchFile.Text:= sEmulatorBatchFile;
             FormCustomCommandLine.PrefixSendLeadingSpace.Checked:= Boolean(PrefixSendLeadingSpace);
             FormCustomCommandLine.AdditionalParameters.Text:= sAdditionalParameters;
           end;
       end;
       // end of function
       FreeAndNil(PrefixList);
       FreeAndNil(ParametersList);
       FreeAndNil(SuffixList);
       FreeAndNil(QuotesList);
     end;
end;

function TFormMain.GenerateParams(pIndex: ShortInt; ListViewHolder: TListView): String;
var
  Loop: ShortInt;
begin
  Result:= '';
  if ListViewHolder.Items.Count > 0 then
     begin
       for Loop:=0 to ListViewHolder.Items.Count-1 do
       begin
         case pIndex of
           0: // prefix
             begin
               if Loop = 0 then
                  Result:= ListViewHolder.Items[Loop].Caption
               else
                  Result:= Result+'¬'+ListViewHolder.Items[Loop].Caption;
             end;
           1: // field
             begin
               if Loop = 0 then
                  Result:= IntToStr(ListViewHolder.Items[Loop].StateIndex)
               else
                  Result:= Result+'¬'+IntToStr(ListViewHolder.Items[Loop].StateIndex);
             end;
           2: // sufix
             begin
               if Loop = 0 then
                  Result:= ListViewHolder.Items[Loop].SubItems[1]
               else
                  Result:= Result+'¬'+ListViewHolder.Items[Loop].SubItems[1];
             end;
           3: // quotes
             begin
               if Loop = 0 then
                  Result:= IntToStr(Ord(Boolean(ListViewHolder.Items[Loop].SubItems[2] = 'Yes')))
               else
                  Result:= Result+'¬'+IntToStr(Ord(Boolean(ListViewHolder.Items[Loop].SubItems[1] = 'Yes')));
             end;
         end;
       end;
         if Result <> '' then
            Result:= Result+';';
     end;
end;

procedure TFormMain.WriteCustomCommandLine(sFileName, sEmulatorFile: String; sParameters: TListView; sAdditionalParameters: String; romID, PrefixLeadingSpace: Integer);
var
  CommandLineFile: THashedStringList;
  Folder, System, pStr: String;
begin
  Folder:= 'ini_files\cmdline\';
  System:= GetSystemFolderName(romID)+'\';

  if CheckReadOnly(FrontendPath+Folder+System+sFileName+'.ini') then
     Exit;

  CommandLineFile:= THashedStringList.Create;
  CommandLineFile.BeginUpdate;
  CommandLineFile.Add('FileName='+sEmulatorFile);
  pStr:= GenerateParams(0, sParameters);
  CommandLineFile.Add('Prefix='+pStr);
  pStr:= GenerateParams(1, sParameters);
  CommandLineFile.Add('PrefixSendLeadingSpace='+IntToStr(PrefixLeadingSpace));
  CommandLineFile.Add('Parameters='+pStr);
  pStr:= GenerateParams(2, sParameters);
  CommandLineFile.Add('Suffix='+pStr);
  pStr:= GenerateParams(3, sParameters);
  CommandLineFile.Add('Quotes='+pStr);
  CommandLineFile.Add('AdditionalParameters='+sAdditionalParameters);
  CommandLineFile.EndUpdate;
  if CheckAndCreateFolder(FrontendPath+Folder+System) then
     CommandLineFile.SaveToFile(FrontendPath+Folder+System+sFileName+'.ini');
  FreeAndNil(CommandLineFile);
end;

procedure TFormMain.DeleteCustomCommandLine(sFileName: String; romID: Integer);
var
  Folder, System: String;
begin
  Folder:= 'ini_files\cmdline\';
  System:= GetSystemFolderName(romID)+'\';
  if GenerateMessage('Delete File', 'You are about the delete "'+
                     FrontendPath+Folder+System+sFileName+'.ini'+'" file'+#13#10+
                     'Are you sure ?', 1) = mrYes then
     DeleteFile(FrontendPath+Folder+System+sFileName+'.ini');
end;

function TFormMain.SelectImageMenu(MenuName: TMenuItem; ImageColorBox: TColorBox): Boolean;
begin
  case MenuName.Checked of
    True : SetImageMode(MenuName.Tag);
    False: MenuName.Click;
  end;
  ImageColorBox.OnSelect(ImageColorBox);
end;

function TFormMain.ReadIniFile(out ErrorString: String): Boolean;
var
  INIFile: TMemIniFile;
  Loop: ShortInt;

  function SetImageFolderZipFile(SystemID: Integer): Boolean;
  var
    Section: String;
  begin
    Section:= GetSystemIniSection(SystemID);
    imgFolderZipFile[SystemID, 0]:= INIFile.ReadString(Section, 'TitleSnapshots', '');
    imgFolderZipFile[SystemID, 1]:= INIFile.ReadString(Section, 'GameSnapshots', '');
    imgFolderZipFile[SystemID, 2]:= INIFile.ReadString(Section, 'Marquees', '');
    imgFolderZipFile[SystemID, 3]:= INIFile.ReadString(Section, 'Flyers', '');
    imgFolderZipFile[SystemID, 4]:= INIFile.ReadString(Section, 'Cabinets', '');
    imgFolderZipFile[SystemID, 5]:= INIFile.ReadString(Section, 'ControlPanels', '');
    imgFolderZipFile[SystemID, 6]:= INIFile.ReadString(Section, 'ControlPanelLayouts', '');
    imgFolderZipFile[SystemID, 7]:= INIFile.ReadString(Section, 'Select', '');
    imgFolderZipFile[SystemID, 8]:= INIFile.ReadString(Section, 'Versus', '');
    imgFolderZipFile[SystemID, 9]:= INIFile.ReadString(Section, 'Wallpapers', '');
    imgFolderZipFile[SystemID, 10]:= INIFile.ReadString(Section, 'Hardware', '');
    imgFolderZipFile[SystemID, 11]:= INIFile.ReadString(Section, 'Custom', '');
  end;

  procedure SetEmulatorVariables(SystemID: Integer);
  var
    SectionString: String;
  begin
    SectionString:= GetSystemIniSection(SystemID);
    EmulatorFile[SystemID]:= INIFile.ReadString(SectionString, 'emu_FileName', '');
    EmulatorVersion[SystemID]:= INIFile.ReadString(SectionString, 'emu_VersionInfo', '');
    EmulatorChecksum[SystemID]:= INIFile.ReadString(SectionString, 'emu_Checksum', '');
    if (EmulatorChecksum[SystemID] = '') and FileExists(EmulatorFile[SystemID]) then
       EmulatorChecksum[SystemID]:= GetMD5_Value(EmulatorFile[SystemID]);
  end;

begin
  Result:= True;
  ErrorString:= '';
  if FormStatus.Visible then
     begin
       FormStatus.LabelMessage.Caption:= GetStatusMessage('ReadIniFile');
       FormStatus.LabelMessage.Refresh;
     end;
  try
    INIFile:= TMemIniFile.Create(FrontendPath+'EmuLoader.ini');

    // read Games Font Type and Color
    SetSelectedColorBox(FormPreferences.GamesBackgroundColor, INIFile.ReadInteger('Appearance', 'GamesListBackgroundColor', TColor(clWindow)));
    MasterFont.Font.Color:= INIFile.ReadInteger('Appearance', 'MasterGameFontColor', 0);
    MasterFont.Font.Name:= INIFile.ReadString('Appearance', 'MasterGameFontName', 'Segoe UI');
    MasterFont.Font.Size:= INIFile.ReadInteger('Appearance', 'MasterGameFontSize', 9);
    MasterFont.Font.Style:= TFontStyles(Byte(INIFile.ReadInteger('Appearance', 'MasterGameFontStyle', 0)));

    CloneFont.Font.Color:= INIFile.ReadInteger('Appearance', 'CloneGameFontColor', 0);
    CloneFont.Font.Name:= INIFile.ReadString('Appearance', 'CloneGameFontName', 'Segoe UI');
    CloneFont.Font.Size:= INIFile.ReadInteger('Appearance', 'CloneGameFontSize', 9);
    CloneFont.Font.Style:= TFontStyles(Byte(INIFile.ReadInteger('Appearance', 'CloneGameFontStyle', 0)));

    PreliminaryFont.Font.Color:= INIFile.ReadInteger('Appearance', 'PreliminaryGameFontColor', TColor(clGray));
    PreliminaryFont.Font.Name:= INIFile.ReadString('Appearance', 'PreliminaryGameFontName', 'Segoe UI');
    PreliminaryFont.Font.Size:= INIFile.ReadInteger('Appearance', 'PreliminaryGameFontSize', 9);
    PreliminaryFont.Font.Style:= TFontStyles(Byte(INIFile.ReadInteger('Appearance', 'PreliminaryGameFontStyle', 8)));

    FormPreferences.GamesTileBackground.Checked:= Boolean(INIFile.ReadInteger('Appearance', 'TileBackground', 1));
    FormPreferences.GamesBackgroundImage.Text:= INIFile.ReadString('Appearance', 'BackgroundImage', '');
    FormPreferences.GamesBackgroundImageEnable.Checked:= Boolean(INIFile.ReadInteger('Appearance', 'BackgroundImageEnabled', 0));

    FormPreferences.GameSelectionAlphaBlend.Position:= INIFile.ReadInteger('Appearance', 'SelectionAlphaBlendFactor', 128);
    FormPreferences.GameSelectionAlphaBlendEnable.Checked:= Boolean(INIFile.ReadInteger('Appearance', 'SelectionAlphaBlendEnabled', 0));

    FormPreferences.SortedColumnColor.Selected:= INIFile.ReadInteger('Appearance', 'SortedColumnBackgroundColor', TColor($00F7F7F7));

    FormPreferences.SelectedGameBoldFont.Checked:= Boolean(INIFile.ReadInteger('Appearance', 'SelectionBoldFont', 1));

    with FormPreferences do
    begin
      SplashLogo.Text:= INIFile.ReadString('Preferences', 'SplashLogoFile', 'resources\images\logo\logo.jpg');
      FixEmptyValue(SplashLogo, 'resources\images\logo\logo.jpg');
      FormMain.LogoFileName:= FormPreferences.SplashLogo.Text;

      if FormStatus.Visible then
         FormStatus.OnActivate(Self);

      // read all images colors
      TitleSnapshotsBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesTitleSnapshotsBackgroundColor', 0);
      GameSnapshotsBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesGameSnapshotsBackgroundColor', 0);
      MarqueesBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesMarqueesBackgroundColor', 0);
      FlyersBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesFlyersBackgroundColor', 0);
      CabinetsBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesCabinetsBackgroundColor', 0);
      ControlPanelsBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesControlPanelsBackgroundColor', 0);
      ControlPanelLayoutsBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesControlPanelLayoutsBackgroundColor', 0);
      SelectBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesSelectBackgroundColor', 0);
      VersusBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesVersusBackgroundColor', 0);
      WallpapersBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesWallpapersBackgroundColor', 0);
      HardwareBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesHardwareBackgroundColor', 0);
      CustomImageBackgroundColor.Selected:= INIFile.ReadInteger('Appearance', 'ImagesCustomBackgroundColor', 0);

      ExtractEmulatorDataDOSBox.ItemIndex:= INIFile.ReadInteger('Preferences', 'DOS_BoxExtractEmuData', 0);
      RunEmulatorDOSBox.ItemIndex:= INIFile.ReadInteger('Preferences', 'DOS_BoxRunEmu', 0);
      if ExtractEmulatorDataDOSBox.ItemIndex = -1 then
         ExtractEmulatorDataDOSBox.ItemIndex:= 0;
      if RunEmulatorDOSBox.ItemIndex = -1 then
         RunEmulatorDOSBox.ItemIndex:= 0;
    end;

    SetEmulatorVariables(1); // MAME
    SetEmulatorVariables(2); // ZiNc
    SetEmulatorVariables(3); // Daphne
    SetEmulatorVariables(4); // AGEMAME
    SetEmulatorVariables(5); // PinMAME
    SetEmulatorVariables(6); // HazeMD

    if FormStatus.Visible then
       begin
         FormStatus.LabelMessage.Caption:= GetStatusMessage('ReadIniFile');
         FormStatus.LabelMessage.Refresh;
       end;

    ErrorString:= '';
    for Loop:=1 to MaxArcadeSystems do
    begin
      if (EmulatorFile[Loop] <> '') and (not FileExists(EmulatorFile[Loop])) then
         begin
           if ErrorString <> '' then
              ErrorString:= ErrorString+#13#10;
           ErrorString:= ErrorString+Format('%s - [emulator.exe not found]', [GetEmuFullDescription(Loop)]);
           Result:= False;
         end;
    end;

    MenuMAMEDefaultSettings.Enabled:= (EmulatorFile[1] <> '') or (FileExists(EmulatorFile[1]));
    MenuZiNcDefaultSettings.Enabled:= (EmulatorFile[2] <> '') or (FileExists(EmulatorFile[2]));
    MenuDaphneDefaultSettings.Enabled:= (EmulatorFile[3] <> '') or (FileExists(EmulatorFile[3]));
    MenuAGEMAMEDefaultSettings.Enabled:= (EmulatorFile[4] <> '') or (FileExists(EmulatorFile[4]));
    MenuPinMAMEDefaultSettings.Enabled:= (EmulatorFile[5] <> '') or (FileExists(EmulatorFile[5]));
    MenuHazeMDDefaultSettings.Enabled:= (EmulatorFile[6] <> '') or (FileExists(EmulatorFile[6]));

    if INIFile.ReadString('Configuration', 'WindowState', 'Normal') = 'Maximized' then
       FormMain.Tag:= 1;

    FormMain.Width:= INIFile.ReadInteger('Configuration', 'ScreenWidth', 750);
    FormMain.Height:= INIFile.ReadInteger('Configuration', 'ScreenHeight', 550);
    PanelScreenshotsArea.Width:= INIFile.ReadInteger('Configuration', 'ScreenshotsSplitterPos', 345);
    MenuStatusBarSize.Tag:= INIFile.ReadInteger('Configuration', 'ToolBarSize', 1);
    case MenuStatusBarSize.Tag of
      0: MenuLargeStatusBar.Click;
      2: MenuSmallStatusBar.Click;
    end;
    FormMain.Left:= INIFile.ReadInteger('Configuration', 'ScreenLeft', (Screen.Width shr 1)-(Width shr 1)-1);
    FormMain.Top:= INIFile.ReadInteger('Configuration', 'ScreenTop', (Screen.Height shr 1)-(Height shr 1)-1);
    MenuViewFullScreen.Tag:= INIFile.ReadInteger('Configuration', 'FullScreen', 0);
    PopupMenuGamesList.Tag:= MenuViewFullScreen.Tag;
    MenuParentalLock.Tag:= INIFile.ReadInteger('Configuration', 'ParentalLock', 0);

    ButtonGameFilterArcade.Tag:= INIFile.ReadInteger('ListFilter', 'Arcade', 0);
    SelectedFilterName:= INIFile.ReadString('ListFilter', 'ArcadeGames', 'allgames');
    if SelectedFilterName = '' then
       SelectedFilterName:= 'allgames';
    LastFilterName:= INIFile.ReadString('ListFilter', 'ArcadeGames_LastFilter', '');
    ButtonGameFilterMasterClone.Tag:= INIFile.ReadInteger('ListFilter', 'MasterClone', 0);
    ButtonGameFilterHaveMiss.Tag:= INIFile.ReadInteger('ListFilter', 'HaveMiss', 0);
    ButtonGameFilterWorkingNonWorking.Tag:= INIFile.ReadInteger('ListFilter', 'WorkingNotWorking', 0);
    ButtonGameFilterHideBios.Down:= Boolean(INIFile.ReadInteger('ListFilter', 'HideBios', 0)); // on / off
    ButtonGameFilterNumberScreens.Tag:= INIFile.ReadInteger('ListFilter', 'NumberScreens', 0);

    if Boolean(INIFile.ReadInteger('ListFilter', 'CPUFilter', 0)) then
       MenuViewCPUFilterBox.Click;

    // set tool bar buttons checked menu items
    PopupGameArcadeFilters.Items[ButtonGameFilterArcade.Tag].Checked:= True;
    PopupGameFilterMasterClone.Items[ButtonGameFilterMasterClone.Tag].Checked:= True;
    PopupGameFilterHaveMiss.Items[ButtonGameFilterHaveMiss.Tag].Checked:= True;
    PopupGameFilterWorkingNonWorking.Items[ButtonGameFilterWorkingNonWorking.Tag].Checked:= True;
    PopupGameFilterNumberScreens.Items[ButtonGameFilterNumberScreens.Tag].Checked:= True;

    PopupGamesUseMAMu_Icons.Tag:= INIFile.ReadInteger('Preferences', 'GamesIcons', 0);
    PopupShowParentIconOnly.Checked:= Boolean(INIFile.ReadInteger('Preferences','ShowOnlyParentIcon', 0));

    ButtonGroupedBlendCloneIcons50Percent.Checked:= Boolean(INIFile.ReadInteger('TreeView', 'BlendIcons', 0));
    if not Boolean(INIFile.ReadInteger('TreeView', 'NodesExpanded', 1)) then
       ButtonGroupedToggleExpandedClosed.Click;

    FormPreferences.TreeViewTreeRoot.Checked:= Boolean(INIFile.ReadInteger('TreeView', 'TreeRoot', 1));
    FormPreferences.TreeViewTreeLines.Checked:= Boolean(INIFile.ReadInteger('TreeView', 'TreeLines', 1));
    FormPreferences.TreeViewHorizontalGridLines.Checked:= Boolean(INIFile.ReadInteger('TreeView', 'HorizontalGridLines', 0));
    FormPreferences.TreeViewVerticalGridLines.Checked:= Boolean(INIFile.ReadInteger('TreeView', 'VerticalGridLines', 0));

    ButtonViewMode.Tag:= INIFile.ReadInteger('Configuration', 'ViewMode', 0);
    if ButtonViewMode.Tag <> 0 then
       PopupMenuViewMode.Items[ButtonViewMode.Tag].Click;

    PopupGameIconSize.Tag:= INIFile.ReadInteger('TreeView', 'IconSize', 1);
    case PopupGameIconSize.Tag of
      0: PopupIconSizeLarge.Click;
      2: PopupIconSizeSmall.Click;
    end;

    // columns settings
    ColumnsProfile[0]:= INIFile.ReadString('Columns', 'Profile', 'default.ini');
    if ColumnsProfile[0] = '' then
       ColumnsProfile[0]:= 'default.ini';
    ColumnsSort[0, 0]:= INIFile.ReadInteger('Columns', 'LastSorted', 0);
    ColumnsSort[0, 1]:= INIFile.ReadInteger('Columns', 'SortDirection', 0); // 0 - Ascending ; 1 - Descending

    for Loop:= 1 to MaxArcadeSystems do
    begin
      ColumnsProfile[Loop]:= INIFile.ReadString('Columns', 'Profile_'+LowerCase(GetSystemIniSection(Loop)), 'default.ini');
      if ColumnsProfile[Loop] = '' then
         ColumnsProfile[Loop]:= 'default.ini';
      ColumnsSort[Loop, 0]:= INIFile.ReadInteger('Columns', 'LastSorted_'+LowerCase(GetSystemIniSection(Loop)), 0);
      ColumnsSort[Loop, 1]:= INIFile.ReadInteger('Columns', 'SortDirection_'+LowerCase(GetSystemIniSection(Loop)), 0); // 0 - Ascending ; 1 - Descending
    end;
    ReadColumnProfile;

    SelectedGameName[0]:= INIFile.ReadString('Selected', 'LastSelected', '');
    SelectedGameID[0]:= INIFile.ReadInteger('Selected', 'LastROM_ID', -1);
    for Loop:= 1 to MaxArcadeSystems do
    begin
      SelectedGameName[Loop]:= INIFile.ReadString('Selected', 'LastSelected_'+LowerCase(GetSystemIniSection(Loop)), '');
      SelectedGameID[Loop]:= INIFile.ReadInteger('Selected', 'LastROM_ID_'+LowerCase(GetSystemIniSection(Loop)), -1);
    end;

    if not Boolean(INIFile.ReadInteger('GameDocuments', 'EnableToolBar', 1)) then
       PopupGameDocsEnableToolBar.Click;

    GameDocumentsLayout1_Top.Tag:= INIFile.ReadInteger('GameDocuments', 'LayoutTop_Height', 151);
    GameDocumentsLayout2_Bottom.Tag:= INIFile.ReadInteger('GameDocuments', 'LayoutBottom_Height', 151);
    GameDocumentsLayout3_Left.Tag:= INIFile.ReadInteger('GameDocuments', 'LayoutLeft_Width', 151);
    GameDocumentsLayout4_Right.Tag:= INIFile.ReadInteger('GameDocuments', 'LayoutRight_Width', 151);

    PanelGameDocuments.Tag:= INIFile.ReadInteger('GameDocuments', 'LayoutIndex', 0);

    if PanelGameDocuments.Tag <> 0 then
       GameDocumentsLayout1_Top.Down:= False;
    case PanelGameDocuments.Tag of
      0: PanelGameDocuments.Height:= GameDocumentsLayout1_Top.Tag;
      1:
        begin
          GameDocumentsLayout2_Bottom.Down:= True;
          GameDocumentsLayout2_Bottom.Click;
        end;
      2:
        begin
          GameDocumentsLayout3_Left. Down:= True;
          GameDocumentsLayout3_Left.Click;
        end;
      3:
        begin
          GameDocumentsLayout4_Right.Down:= True;
          GameDocumentsLayout4_Right.Click;
        end;
    end;

    with FormPreferences do
    begin
      // read all Automatic Game Info Color and Font Type
      SetSelectedColorBox(GameDocumentsBackgroundColor, INIFile.ReadInteger('GameDocuments', 'BackgroundColor', TColor(clWindow)));
      MAMEInfoTextHolder.Font.Color:= INIFile.ReadInteger('GameDocuments', 'FontColor', 0);
      MAMEInfoTextHolder.Font.Name:= INIFile.ReadString('GameDocuments', 'FontName', 'Segoe UI');
      MAMEInfoTextHolder.Font.Size:= INIFile.ReadInteger('GameDocuments', 'FontSize', 9);
      MAMEInfoTextHolder.Font.Style:= TFontStyles(Byte(INIFile.ReadInteger('GameDocuments', 'FontType', 0)));

      NewDescriptionFormat.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'NewDescriptionFormat', 0));
      if not (Boolean(INIFile.ReadInteger('Preferences', 'ShowEmuVersionSystemDescription', 1))) then
         ShowEmuVersionSystemDescription.Checked:= False;

      MenuViewForceQuotesCommandLine.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'ForceQuotesCommandLine', 0));
      MenuViewForceQuotesCommandLine.OnClick(Self);

      RunCustomGameSettingsByDefault.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'RunCustomGameSettingsByDefault', 1));

      // "Games List" main menu
      MenuGamesEnableMultipleSelection.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'MultipleGamesSelect', 0));
      MenuGamesEnableMultipleSelection.OnClick(Self);

      MenuIncrementalSearch.Tag:= INIFile.ReadInteger('Preferences', 'IncrementalSearch', 0);
      MenuIncrementalSearch.Items[MenuIncrementalSearch.Tag].Checked:= True;

      MenuGamesFillAllCloneEntries.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'FillAllCloneEntries', 0));
      FormPreferences.SmoothScroll.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'SmoothScroll', 0));
      EnableGamePlayTime_Played.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'EnableGamePlayTime_Played', 0));

      AutomaticGameInformation1.ItemIndex:= INIFile.ReadInteger('GameDocuments', 'AutoGameInfo1', 1);
      AutomaticGameInformation2.ItemIndex:= INIFile.ReadInteger('GameDocuments', 'AutoGameInfo2', 2);
      AutomaticGameInformation3.ItemIndex:= INIFile.ReadInteger('GameDocuments', 'AutoGameInfo3', 3);
      AutomaticGameInformation4.ItemIndex:= INIFile.ReadInteger('GameDocuments', 'AutoGameInfo4', 4);
      AutomaticGameInformation5.ItemIndex:= INIFile.ReadInteger('GameDocuments', 'AutoGameInfo5', 5);
      AutomaticGameInformationOpenWindow.Checked:= Boolean(INIFile.ReadInteger('GameDocuments', 'AutoGameInfoOpenWindow', 0));

      // Miscellaneous
      ShowZipErrorMessages.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'ZipFileErrors', 0));
      ReadOnlyMessage.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'ReadOnlyMessage', 0));
      BiosSetWarning.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'BiosSetWarning', 1));

      MinimizeFrontendToRunGames.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'MinimizeToTrayRunGames', 1));

      MenuViewEmulatorFullCommandLine.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'ShowEmulatorFullCommandLine', 0));

      StartupGamesListNotFound.ItemIndex:= INIFile.ReadInteger('Preferences', 'StartupGameNotFound', 0);
      StartupNewBinaryFound.ItemIndex:= INIFile.ReadInteger('Preferences', 'StartupNewBinaryFound', 0);
      case RunEmulatorStartup.Enabled of
        True:
          begin
            RunEmulatorStartup.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'StartupRunEmulator', 1));
            EmulatorRunOnce:= RunEmulatorStartup.Checked;
          end;
        False:
          begin
            RunEmulatorStartup.Checked:= False;
            EmulatorRunOnce:= False
          end;
      end;
      // General Folders
      // Emu Loader Folders & Zip Files
      MAMu_Icons.Text:= INIFile.ReadString('FoldersZip', 'Icons', 'icons\icons.zip');
      FolderGamesFAQ.Text:= INIFile.ReadString('FoldersZip', 'GamesFAQ', 'faq');
      FixEmptyValue(MAMu_Icons, 'icons\icons.zip');
      FixEmptyValue(FolderGamesFAQ, 'faq');

      // MAME Tab
      // MAME Extra Options
      for Loop:= 1 to MaxArcadeSystems do
          SetImageFolderZipFile(Loop);

      ZiNc_BreakSettingsCFG.Checked:= Boolean(INIFile.ReadInteger(GetSystemIniSection(2), 'BreakSettingsCFG', 0));
      ZiNcUseMAMEGamesInfo.Checked:= Boolean(INIFile.ReadInteger(GetSystemIniSection(2), 'UseMAMEGamesInfo', 1));

      Daphne_NoLog.Checked:= Boolean(INIFile.ReadInteger(GetSystemIniSection(3), 'NoCreateLogFile', 1));
    end;
    MenuDaphneRunFullScreen.Checked:= Boolean(INIFile.ReadInteger(GetSystemIniSection(3), 'RunFullScreen', 0));

    PopupAutomaticGameInformation.Tag:= INIFile.ReadInteger('GameDocuments', 'AutoGameInformation', 0);

    FavoriteUser:= INIFile.ReadString('Favorites', 'User', 'Default');
    if FavoriteUser = '' then
       FavoriteUser:= 'Default';
    StatusBar_FavoritesProfile.Hint:= 'Favorites Profile: '+FavoriteUser;
    FavoriteUserFile:= GetFavoriteUserFileName(FavoriteUser);

    // Title Snapshot, Game Snapshot, Marquee, Flyer, Cabinet, Control Panel, Control Panel Layout
    // Select, Versus, Wallpapers, Hardware, Custom 1, Custom 2, Custom 3
    with FormPreferences do
    begin
      DescriptionMarquees.Text:= INIFile.ReadString('Images', 'Marquees_title', 'Marquees');
      DescriptionFlyers.Text:= INIFile.ReadString('Images', 'Flyers_title', 'Flyers');
      DescriptionCabinets.Text:= INIFile.ReadString('Images', 'Cabinets_title', 'Cabinets');
      DescriptionControlPanels.Text:= INIFile.ReadString('Images', 'ControlPanels_title', 'Control Panels');
      DescriptionControlPanelLayouts.Text:= INIFile.ReadString('Images', 'ControlPanelLayouts_title', 'Control Panel Layouts');
      DescriptionWallpapers.Text:= INIFile.ReadString('Images', 'Wallpapers_title', 'Wallpapers');
      DescriptionHardware.Text:= INIFile.ReadString('Images', 'Hardware_title', 'Hardware');
      DescriptionCustomImage.Text:= INIFile.ReadString('Images', 'Custom_title', 'Custom');
      EnableTitleSnapshots.Checked:= Boolean(INIFile.ReadInteger('Images', 'TitleSnapshots_enable', 1));
      EnableMarquees.Checked:= Boolean(INIFile.ReadInteger('Images', 'Marquees_enable', 1));
      EnableFlyers.Checked:= Boolean(INIFile.ReadInteger('Images', 'Flyers_enable', 1));
      EnableCabinets.Checked:= Boolean(INIFile.ReadInteger('Images', 'Cabinets_enable', 1));
      EnableControlPanels.Checked:= Boolean(INIFile.ReadInteger('Images', 'ControlPanels_enable', 1));
      EnableControlPanelLayouts.Checked:= Boolean(INIFile.ReadInteger('Images', 'ControlPanelLayouts_enable', 1));
      EnableSelect.Checked:= Boolean(INIFile.ReadInteger('Images', 'Select_enable', 1));
      EnableVersus.Checked:= Boolean(INIFile.ReadInteger('Images', 'Versus_enable', 1));
      EnableWallpapers.Checked:= Boolean(INIFile.ReadInteger('Images', 'Wallpapers_enable', 1));
      EnableHardware.Checked:= Boolean(INIFile.ReadInteger('Images', 'Hardware_enable', 1));
      EnableCustomImage.Checked:= Boolean(INIFile.ReadInteger('Images', 'Custom_enable', 0));
    end;
    ButtonImagesViewMode.Tag:= INIFile.ReadInteger('Images', 'ImageViewMode', 1);
    case ButtonImagesViewMode.Tag of
       0: SelectImageMenu(ButtonShowTitleSnapshots, FormPreferences.TitleSnapshotsBackgroundColor);
       1: SelectImageMenu(ButtonShowGameSnapShots, FormPreferences.GameSnapshotsBackgroundColor);
       2: SelectImageMenu(ButtonShowMarquees, FormPreferences.MarqueesBackgroundColor);
       3: SelectImageMenu(ButtonShowFlyers, FormPreferences.FlyersBackgroundColor);
       4: SelectImageMenu(ButtonShowCabinets, FormPreferences.CabinetsBackgroundColor);
       5: SelectImageMenu(ButtonShowControlPanels, FormPreferences.ControlPanelsBackgroundColor);
       6: SelectImageMenu(ButtonShowControlPanelLayouts, FormPreferences.ControlPanelLayoutsBackgroundColor);
       7: SelectImageMenu(ButtonShowSelect, FormPreferences.SelectBackgroundColor);
       8: SelectImageMenu(ButtonShowVersus, FormPreferences.VersusBackgroundColor);
       9: SelectImageMenu(ButtonShowWallpapers, FormPreferences.WallpapersBackgroundColor);
      10: SelectImageMenu(ButtonShowHardware, FormPreferences.HardwareBackgroundColor);
      11: SelectImageMenu(ButtonShowCustomImage, FormPreferences.CustomImageBackgroundColor);
    end;

    PopupImageStretch.Tag:= INIFile.ReadInteger('Images', 'Stretch', 1);
    PopupImageStretchLarger.Tag:= INIFile.ReadInteger('Images', 'StretchLargerImages', 0);
    PopupImageScreenAspectRatio.Checked:= Boolean(INIFile.ReadInteger('Images', 'ScreenAspectRatio', 1));

    MenuImagesELFormat.Checked:= Boolean(INIFile.ReadInteger('Images', 'UseELFormat', 1));
    MenuImagesNewFormat.Checked:= Boolean(INIFile.ReadInteger('Images', 'UseNewFormat', 1));
    MenuImagesOldFormat.Checked:= Boolean(INIFile.ReadInteger('Images', 'UseOldFormat', 0));

    with FormPreferences do
    begin
      MenuImageResampler.Tag:= INIFile.ReadInteger('Images', 'ImageResampler', 8);
      PopupImageDisplayParent.Checked:= Boolean(INIFile.ReadInteger('Images', 'DisplayParent', 1));
      CycleImageTypes.Checked:= Boolean(INIFile.ReadInteger('Images', 'CycleImageTypes', 0));
      ButtonShowMAWSGameInfo.Tag:= INIFile.ReadInteger('Images', 'ShowMAWSGameInfo', 0);
      FormPreferences.UpdatePictureTypesDescriptions;
      if PopupImageStretchLarger.Tag = 1 then
         PopupImageStretchLarger.Checked:= True;
      case PopupImageStretch.Tag of
        0: //False
          begin
            PopupImageStretch.Tag:= 1;
            PopupImageStretch.Checked:= False;
            PopupImageStretch.Tag:= 0;
          end;
        1: PopupImageStretch.Tag:= 0;
      end;
    end;

    MenuShowImages.Tag:= INIFile.ReadInteger('Images', 'ShowImages', 1);
    with FormPreferences do
    begin
      XArcade.Checked:= Boolean(INIFile.ReadInteger('X-Arcade', 'UseXArcade', 0));

      if not XArcade.Checked then
         HotRodSE.Checked:= Boolean(INIFile.ReadInteger('HotRodSE', 'UseHotRodSE', 0));

      if (not XArcade.Checked) and (not HotRodSE.Checked) then
         SlikStik.Checked:= Boolean(INIFile.ReadInteger('SlikStik', 'UseSlikStik', 0));
      SlikStikSwap2ndPlayerStick.Checked:= Boolean(INIFile.ReadInteger('SlikStik', 'Swap2ndStick', 0));

      if (not XArcade.Checked) and (not HotRodSE.Checked) and (not SlikStik.Checked) then
         Devastator2.Checked:= Boolean(INIFile.ReadInteger('DevastatorII', 'UseDevastatorII', 0));

      // FMOD settings
      PlayAudio.Tag:= INIFile.ReadInteger('Audio', 'PlayAudio', 0);
      AudioVolume.Position:= INIFile.ReadInteger('Audio', 'Volume', 200);

      for Loop:= 1 to MaxArcadeSystems do
          AudioFolders[Loop]:= INIFile.ReadString('Audio', 'folder_'+LowerCase(GetSystemIniSection(Loop)), '');

      OutputDevice.Tag:= INIFile.ReadInteger('Audio', 'OutputDevice', 0);
      MixerType.ItemIndex:= INIFile.ReadInteger('Audio', 'MixerType', 4);
      OutputRate.ItemIndex:= INIFile.ReadInteger('Audio', 'OutputRate', 3);

      PlayMNG.Tag:= INIFile.ReadInteger('Video', 'PlayMNG', 0);
      AudioVideoUseParent.Checked:= Boolean(INIFile.ReadInteger('Video', 'UseParent', 1));
      AudioVideoLoop.Checked:= Boolean(INIFile.ReadInteger('Video', 'Loop', 0));
      for Loop:= 1 to MaxArcadeSystems do
          MNGFolders[Loop]:= INIFile.ReadString('Video', 'folder_'+LowerCase(GetSystemIniSection(Loop)), '');

      // Random Game Preview
      WarningPanelAnimation.Checked:= Boolean(INIFile.ReadInteger('RandomGamePreview', 'WarningPanelAnimation', 1));
      RestoreSelectedGame.Checked:= Boolean(INIFile.ReadInteger('RandomGamePreview', 'RestoreSelectedGame', 1));
      NumberGamesToRun.Position:= INIFile.ReadInteger('RandomGamePreview', 'NumberGamesToRun', 2);
      GamePreviewRunningTime.Position:= INIFile.ReadInteger('RandomGamePreview', 'RunningTime', 300000);
      UseAvailableGamesOnly.Position:= INIFile.ReadInteger('RandomGamePreview', 'UseAvailableGamesOnly', 10);
      PauseBetweenGames.Position:= INIFile.ReadInteger('RandomGamePreview', 'PauseBetweenGames', 5000);
      PauseBeforeEmulatorStarts.Position:= INIFile.ReadInteger('RandomGamePreview', 'PauseBeforeEmulatorStarts', 3000);
      BlendPreviewWindowFactor.Position:= INIFile.ReadInteger('RandomGamePreview', 'WindowBlendFactor', 220);
    end;

    ToolBarPanel.Tag:= INIFile.ReadInteger('ToolBar', 'ToolBar_visible', 1);
    ToolBarPanel.Visible:= Boolean(ToolBarPanel.Tag = 1);
    ButtonViewMode.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'ViewMode_visible', 1));
    ButtonGameFilterArcade.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterSystems_visible', 1));
    ButtonGameFilterMain.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterMain_visible', 1));
    ButtonGameFilterMasterClone.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterMasterClone_visible', 1));
    ButtonGameFilterHaveMiss.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterHaveMiss_visible', 1));
    ButtonGameFilterWorkingNonWorking.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterWorkNonWork_visible', 1));
    ButtonGameFilterHideBios.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterHideBios_visible', 1));
    ButtonGameFilterNumberScreens.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'FilterNumberScreens', 1));
    ButtonImagesViewMode.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'ImagesViewMode_visible', 1));
    ButtonRandomGame.Visible:= Boolean(INIFile.ReadInteger('ToolBar', 'RandomGame_visible', 1));

    ImagesToolbarPanel.Tag:= INIFile.ReadInteger('ImagesToolBar', 'ToolBar_visible', 1);
    ImagesToolbarPanel.Visible:= Boolean(ImagesToolbarPanel.Tag = 1);
    ButtonPreviousImage.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'PreviousImage', 1));
    ButtonNextImage.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'NextImage', 1));
    ButtonPreviousType.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'PreviousType', 1));
    ButtonNextType.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'NextType', 1));
    ButtonImageVisualEffects.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'VisualEffects', 1));
    ButtonImageToolBarViewMode.Visible:= Boolean(INIFile.ReadInteger('ImagesToolBar', 'ImageViewMode', 1));

    StatusBarPanel.Tag:= INIFile.ReadInteger('StatusBar', 'ToolBar_visible', 1);
    StatusBarPanel.Visible:= Boolean(StatusBarPanel.Tag = 1);
    StatusBar_GameName.Visible:= Boolean(INIFile.ReadInteger('StatusBar', 'GameName_visible', 1));
    StatusBar_GameSize.Visible:= Boolean(INIFile.ReadInteger('StatusBar', 'GameSize_visible', 1));
    StatusBar_TotalEntries.Visible:= Boolean(INIFile.ReadInteger('StatusBar', 'TotalEntries_visible', 1));
    StatusBar_FavoritesProfile.Visible:= Boolean(INIFile.ReadInteger('StatusBar', 'FavoritesProfile_visible', 1));
    MenuGameSizeFormat.Tag:= INIFile.ReadInteger('StatusBar', 'GameSizeFormat', 0);
    if not MenuGameSizeFormat.Items[MenuGameSizeFormat.Tag].Checked then
       MenuGameSizeFormat.Items[MenuGameSizeFormat.Tag].Click;
  finally
    FreeAndNil(INIFile);
  end;

  // Audit
  try
    INIFile:= TMemIniFile.Create(FrontendPath+'ini_files\el_extras.ini');
    PopupAuditDownloadAddress.Hint:= INIFile.ReadString('Audit', 'DownloadAddress', 'ftp://user:pass@yourlink.net/mame_roms/');
    PopupAuditNotUsedFiles.Checked:= Boolean(INIFile.ReadInteger('Audit', 'NotUsedFiles', 0));
  finally
    FreeAndNil(INIFile);
  end;
  LoadFoldersAllSystems;
end;

procedure TFormMain.UpdateIniFile(EmulatorsOnly: Boolean);
var
  INIFile: TMemIniFile;
  Loop: Integer;

  function SaveSnapFolderZipFile(SystemID: Integer): Boolean;
  var
    Section: String;

    function UpdateEntry(EntryName: String; imgType: ShortInt): Boolean;
    begin
      if imgFolderZipFile[SystemID, imgType] <> '' then
         INIFile.WriteString(Section, EntryName, imgFolderZipFile[SystemID, imgType])
      else
         INIFile.DeleteKey(Section, EntryName);
    end;

  begin
    Section:= GetSystemIniSection(SystemID);
    UpdateEntry('TitleSnapshots', 0);
    UpdateEntry('GameSnapshots', 1);
    UpdateEntry('Marquees', 2);
    UpdateEntry('Flyers', 3);
    UpdateEntry('Cabinets', 4);
    UpdateEntry('ControlPanels', 5);
    UpdateEntry('ControlPanelLayouts', 6);
    UpdateEntry('Select', 7);
    UpdateEntry('Versus', 8);
    UpdateEntry('Wallpapers', 9);
    UpdateEntry('Hardware', 10);
    UpdateEntry('Custom', 11);
  end;

  function WriteEmulatorROMsFolders(SystemID: Integer): Boolean;
  var
    FolderString: String;
    folderLoop: Integer;
  begin
    if Assigned(emuROMsFolders[SystemID]) and (emuROMsFolders[SystemID].Count > 0) then
       begin
         FolderString:= '';
         for folderLoop:=0 to emuROMsFolders[SystemID].Count-1 do
         begin
           if FolderString = '' then
              FolderString:= emuROMsFolders[SystemID].Strings[folderLoop]
           else
              FolderString:= FolderString+';'+emuROMsFolders[SystemID].Strings[folderLoop]
         end;
         INIFile.WriteString(GetSystemIniSection(SystemID), 'roms_path', FolderString);
       end
    else
       INIFile.DeleteKey(GetSystemIniSection(SystemID), 'roms_path');
  end;

  procedure WriteEmulatorVariables(SystemID: Integer);
  var
    SectionString: String;
  begin
    if EmulatorFile[SystemID] <> '' then
       begin
         SectionString:= GetSystemIniSection(SystemID);
         INIFile.WriteString(SectionString, 'emu_FileName', EmulatorFile[SystemID]);
         INIFile.WriteString(SectionString, 'emu_VersionInfo', EmulatorVersion[SystemID]);
         INIFile.WriteString(SectionString, 'emu_Checksum', EmulatorChecksum[SystemID]);
       end
    else
       begin
         INIFile.DeleteKey(SectionString, 'emu_FileName');
         INIFile.DeleteKey(SectionString, 'emu_VersionInfo');
         INIFile.DeleteKey(SectionString, 'emu_Checksum');
       end;
  end;

begin
  if CheckReadOnly(FrontendPath+'EmuLoader.ini') then
     Exit;
  try
    INIFile:= TMemIniFile.Create(FrontendPath+'EmuLoader.ini');
    INIFile.Clear;

    INIFile.WriteInteger('Configuration', 'ViewMode', ButtonViewMode.Tag);
    case FormMain.WindowState of
      wsNormal   : INIFile.WriteString('Configuration', 'WindowState', 'Normal');
      wsMaximized: INIFile.WriteString('Configuration', 'WindowState', 'Maximized');
      else
        INIFile.WriteString('Configuration', 'WindowState', 'Normal');
    end;

    if ((FormMain.WindowState <> wsMaximized) and (not MenuViewFullScreen.Checked)) then
       begin
         INIFile.WriteInteger('Configuration', 'ScreenTop', FormMain.Top);
         INIFile.WriteInteger('Configuration', 'ScreenLeft', FormMain.Left);
         INIFile.WriteInteger('Configuration', 'ScreenWidth', FormMain.Width);
         INIFile.WriteInteger('Configuration', 'ScreenHeight', FormMain.Height);
       end;

    INIFile.WriteInteger('Configuration', 'ScreenshotsSplitterPos', PanelScreenshotsArea.Width);
    INIFile.WriteInteger('Configuration', 'SmallToolBar', Ord(MenuSmallToolBar.Checked));
    INIFile.WriteInteger('Configuration', 'ToolBarSize', MenuStatusBarSize.Tag);

    INIFile.WriteInteger('Configuration', 'FullScreen', Ord(MenuViewFullScreen.Checked));

    INIFile.WriteInteger('Configuration', 'ParentalLock', Ord(MenuParentalLock.Checked));

    INIFile.WriteInteger('ListFilter', 'Arcade', ButtonGameFilterArcade.Tag);

    INIFile.WriteString('Columns', 'Profile', ColumnsProfile[0]);
    UpdateColumnProfile(False, True);

    INIFile.WriteInteger('Columns', 'LastSorted', ColumnsSort[0, 0]);
    INIFile.WriteInteger('Columns', 'SortDirection', ColumnsSort[0, 1]); // 0 - Ascending ; 1 - Descending

    for Loop:= 1 to MaxArcadeSystems do
    begin
      INIFile.WriteString('Columns', 'Profile_'+LowerCase(GetSystemIniSection(Loop)), ColumnsProfile[Loop]);
      INIFile.WriteInteger('Columns', 'LastSorted_'+LowerCase(GetSystemIniSection(Loop)), ColumnsSort[Loop, 0]);
      INIFile.WriteInteger('Columns', 'SortDirection_'+LowerCase(GetSystemIniSection(Loop)), ColumnsSort[Loop, 1]);
    end;

    INIFile.WriteString('Selected', 'LastSelected', SelectedGameName[0]);
    INIFile.WriteInteger('Selected', 'LastROM_ID', SelectedGameID[0]);

    INIFile.WriteInteger('GameDocuments', 'EnableToolBar', Ord(PopupGameDocsEnableToolBar.Checked));

    INIFile.WriteInteger('GameDocuments', 'LayoutTop_Height', GameDocumentsLayout1_Top.Tag);
    INIFile.WriteInteger('GameDocuments', 'LayoutBottom_Height', GameDocumentsLayout2_Bottom.Tag);
    INIFile.WriteInteger('GameDocuments', 'LayoutLeft_Width', GameDocumentsLayout3_Left.Tag);
    INIFile.WriteInteger('GameDocuments', 'LayoutRight_Width', GameDocumentsLayout4_Right.Tag);

    INIFile.WriteInteger('GameDocuments', 'LayoutIndex', PanelGameDocuments.Tag);

    for Loop:= 1 to MaxArcadeSystems do
    begin
      INIFile.WriteString('Selected', 'LastSelected_'+LowerCase(GetSystemIniSection(Loop)), SelectedGameName[Loop]);
      INIFile.WriteInteger('Selected', 'LastROM_ID_'+LowerCase(GetSystemIniSection(Loop)), SelectedGameID[Loop]);
    end;

    INIFile.WriteString('ListFilter', 'ArcadeGames', SelectedFilterName);
    INIFile.WriteString('ListFilter', 'ArcadeGames_LastFilter', LastFilterName);
    INIFile.WriteInteger('ListFilter', 'MasterClone', ButtonGameFilterMasterClone.Tag);
    INIFile.WriteInteger('ListFilter', 'HaveMiss', ButtonGameFilterHaveMiss.Tag);
    INIFile.WriteInteger('ListFilter', 'WorkingNotWorking', ButtonGameFilterWorkingNonWorking.Tag);
    INIFile.WriteInteger('ListFilter', 'HideBios', Ord(ButtonGameFilterHideBios.Down)); // on / off
    INIFile.WriteInteger('ListFilter', 'NumberScreens', Ord(ButtonGameFilterNumberScreens.Tag));

    INIFile.WriteInteger('ListFilter', 'CPUFilter', Ord(MenuViewCPUFilterBox.Checked));

    INIFile.WriteInteger('Appearance', 'GamesListBackgroundColor', FormPreferences.GamesBackgroundColor.Selected);
    INIFile.WriteInteger('Appearance', 'MasterGameFontColor', MasterFont.Font.Color);
    INIFile.WriteString('Appearance', 'MasterGameFontName', MasterFont.Font.Name);
    INIFile.WriteInteger('Appearance', 'MasterGameFontSize', MasterFont.Font.Size);
    INIFile.WriteInteger('Appearance', 'MasterGameFontStyle', Byte(MasterFont.Font.Style));

    INIFile.WriteInteger('Appearance', 'CloneGameFontColor', CloneFont.Font.Color);
    INIFile.WriteString('Appearance', 'CloneGameFontName', CloneFont.Font.Name);
    INIFile.WriteInteger('Appearance', 'CloneGameFontSize', CloneFont.Font.Size);
    INIFile.WriteInteger('Appearance', 'CloneGameFontStyle', Byte(CloneFont.Font.Style));

    INIFile.WriteInteger('Appearance', 'PreliminaryGameFontColor', PreliminaryFont.Font.Color);
    INIFile.WriteString('Appearance', 'PreliminaryGameFontName', PreliminaryFont.Font.Name);
    INIFile.WriteInteger('Appearance', 'PreliminaryGameFontSize', PreliminaryFont.Font.Size);
    INIFile.WriteInteger('Appearance', 'PreliminaryGameFontStyle', Byte(PreliminaryFont.Font.Style));

    INIFile.WriteInteger('Appearance', 'TileBackground', Ord(FormPreferences.GamesTileBackground.Checked));
    INIFile.WriteInteger('Appearance', 'BackgroundImageEnabled', Ord(FormPreferences.GamesBackgroundImageEnable.Checked));
    INIFile.WriteString('Appearance', 'BackgroundImage', FormPreferences.GamesBackgroundImage.Text);

    INIFile.WriteInteger('Appearance', 'SelectionAlphaBlendEnabled', Ord(FormPreferences.GameSelectionAlphaBlendEnable.Checked));
    INIFile.WriteInteger('Appearance', 'SelectionAlphaBlendFactor', FormPreferences.GameSelectionAlphaBlend.Position);

    INIFile.WriteInteger('Appearance', 'SortedColumnBackgroundColor', FormPreferences.SortedColumnColor.Selected);
    INIFile.WriteInteger('Appearance', 'SelectionBoldFont', Ord(FormPreferences.SelectedGameBoldFont.Checked));

    INIFile.WriteInteger('TreeView', 'IconSize', PopupGameIconSize.Tag);
    INIFile.WriteInteger('TreeView', 'BlendIcons', Ord(ButtonGroupedBlendCloneIcons50Percent.Checked));
    INIFile.WriteInteger('TreeView', 'NodesExpanded', Ord(ButtonGroupedToggleExpandedClosed.Checked));
    INIFile.WriteInteger('TreeView', 'TreeRoot', Ord(FormPreferences.TreeViewTreeRoot.Checked));
    INIFile.WriteInteger('TreeView', 'TreeLines', Ord(FormPreferences.TreeViewTreeLines.Checked));
    INIFile.WriteInteger('TreeView', 'HorizontalGridLines', Ord(FormPreferences.TreeViewHorizontalGridLines.Checked));
    INIFile.WriteInteger('TreeView', 'VerticalGridLines', Ord(FormPreferences.TreeViewVerticalGridLines.Checked));

    INIFile.WriteInteger('Preferences', 'GamesIcons', Ord(PopupGamesUseMAMu_Icons.Checked));
    INIFile.WriteInteger('Preferences', 'ShowOnlyParentIcon', Ord(PopupShowParentIconOnly.Checked));

    with FormPreferences do
    begin
        // update all images custom colors
      INIFile.WriteInteger('Appearance', 'ImagesTitleSnapshotsBackgroundColor', TitleSnapshotsBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesGameSnapshotsBackgroundColor', GameSnapshotsBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesMarqueesBackgroundColor', MarqueesBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesFlyersBackgroundColor', FlyersBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesCabinetsBackgroundColor', CabinetsBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesControlPanelsBackgroundColor', ControlPanelsBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesControlPanelLayoutsBackgroundColor', ControlPanelLayoutsBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesSelectBackgroundColor', SelectBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesVersusBackgroundColor', VersusBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesWallpapersBackgroundColor', WallpapersBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesHardwareBackgroundColor', HardwareBackgroundColor.Selected);
      INIFile.WriteInteger('Appearance', 'ImagesCustomBackgroundColor', CustomImageBackgroundColor.Selected);

      // update all Automatic Game Info Color and Font Type
      INIFile.WriteInteger('GameDocuments', 'BackgroundColor', GameDocumentsBackgroundColor.Selected);
      INIFile.WriteInteger('GameDocuments', 'FontColor', MAMEInfoTextHolder.Font.Color);
      INIFile.WriteString('GameDocuments', 'FontName', MAMEInfoTextHolder.Font.Name);
      INIFile.WriteInteger('GameDocuments', 'FontSize', MAMEInfoTextHolder.Font.Size);
      INIFile.WriteInteger('GameDocuments', 'FontType', Byte(MAMEInfoTextHolder.Font.Style));

      INIFile.WriteInteger('Preferences', 'NewDescriptionFormat', Ord(NewDescriptionFormat.Checked));
      INIFile.WriteInteger('Preferences', 'ShowEmuVersionSystemDescription', Ord(ShowEmuVersionSystemDescription.Checked));

      INIFile.WriteInteger('Preferences', 'ForceQuotesCommandLine', Ord(MenuViewForceQuotesCommandLine.Checked));
      INIFile.WriteInteger('GameDocuments', 'AutoGameInformation', Ord(PopupAutomaticGameInformation.Checked));

      INIFile.WriteInteger('GameDocuments', 'AutoGameInfo1', AutomaticGameInformation1.ItemIndex);
      INIFile.WriteInteger('GameDocuments', 'AutoGameInfo2', AutomaticGameInformation2.ItemIndex);
      INIFile.WriteInteger('GameDocuments', 'AutoGameInfo3', AutomaticGameInformation3.ItemIndex);
      INIFile.WriteInteger('GameDocuments', 'AutoGameInfo4', AutomaticGameInformation4.ItemIndex);
      INIFile.WriteInteger('GameDocuments', 'AutoGameInfo5', AutomaticGameInformation5.ItemIndex);
      INIFile.WriteInteger('GameDocuments', 'AutoGameInfoOpenWindow', Ord(AutomaticGameInformationOpenWindow.Checked));

      if ExtractEmulatorDataDOSBox.ItemIndex = -1 then
         INIFile.WriteInteger('Preferences', 'DOS_BoxExtractEmuData', 0)
      else
         INIFile.WriteInteger('Preferences', 'DOS_BoxExtractEmuData', ExtractEmulatorDataDOSBox.ItemIndex);
      if RunEmulatorDOSBox.ItemIndex = -1 then
         INIFile.WriteInteger('Preferences', 'DOS_BoxRunEmu', 0)
      else
         INIFile.WriteInteger('Preferences', 'DOS_BoxRunEmu', RunEmulatorDOSBox.ItemIndex);

      INIFile.WriteString('FoldersZip', 'Icons', FormPreferences.MAMu_Icons.Text);
      INIFile.WriteString('FoldersZip', 'GamesFAQ', FormPreferences.FolderGamesFAQ.Text);

      // Miscellaneous
      INIFile.WriteInteger('Preferences', 'ZipFileErrors', Ord(ShowZipErrorMessages.Checked));
      INIFile.WriteInteger('Preferences', 'ReadOnlyMessage', Ord(ReadOnlyMessage.Checked));
      INIFile.WriteInteger('Preferences', 'BiosSetWarning', Ord(BiosSetWarning.Checked));

      INIFile.WriteInteger('Preferences', 'MinimizeToTrayRunGames', Ord(MinimizeFrontendToRunGames.Checked));

      INIFile.WriteInteger('Preferences', 'StartupGameNotFound', StartupGamesListNotFound.ItemIndex);
      INIFile.WriteInteger('Preferences', 'StartupNewBinaryFound', StartupNewBinaryFound.ItemIndex);
      case RunEmulatorStartup.Enabled of
        True : INIFile.WriteInteger('Preferences', 'StartupRunEmulator', Ord(RunEmulatorStartup.Checked));
        False: INIFile.WriteInteger('Preferences', 'StartupRunEmulator', 0);
      end;

      // "Games List" main menu
      INIFile.WriteInteger('Preferences', 'MultipleGamesSelect', Ord(MenuGamesEnableMultipleSelection.Checked));
      INIFile.WriteInteger('Preferences', 'IncrementalSearch', MenuIncrementalSearch.Tag);
      INIFile.WriteInteger('Preferences', 'FillAllCloneEntries', Ord(MenuGamesFillAllCloneEntries.Checked));

      INIFile.WriteInteger('Preferences', 'RunCustomGameSettingsByDefault', Ord(RunCustomGameSettingsByDefault.Checked));
      INIFile.WriteInteger('Preferences', 'SmoothScroll', Ord(FormPreferences.SmoothScroll.Checked));

      INIFile.WriteInteger('Preferences', 'EnableGamePlayTime_Played', Ord(EnableGamePlayTime_Played.Checked));


      // Systems sections options
      INIFile.WriteInteger(GetSystemIniSection(2), 'BreakSettingsCFG', Ord(ZiNc_BreakSettingsCFG.Checked));
      INIFile.WriteInteger(GetSystemIniSection(2), 'UseMAMEGamesInfo', Ord(ZiNcUseMAMEGamesInfo.Checked));

      INIFile.WriteInteger(GetSystemIniSection(3), 'NoCreateLogFile', Ord(Daphne_NoLog.Checked));
    end;

    WriteEmulatorROMsFolders(2); // ZiNc

    INIFile.WriteInteger(GetSystemIniSection(3), 'RunFullScreen', Ord(MenuDaphneRunFullScreen.Checked));

    INIFile.WriteInteger('Preferences', 'ShowEmulatorFullCommandLine', Ord(MenuViewEmulatorFullCommandLine.Checked));
    INIFile.WriteString('Favorites', 'User', FavoriteUser);

    INIFile.WriteInteger('Images', 'Stretch', Ord(PopupImageStretch.Checked));
    INIFile.WriteInteger('Images', 'StretchLargerImages', Ord(PopupImageStretchLarger.Checked));
    INIFile.WriteInteger('Images', 'ScreenAspectRatio', Ord(PopupImageScreenAspectRatio.Checked));

    INIFile.WriteInteger('Images', 'UseELFormat', Ord(MenuImagesELFormat.Checked));
    INIFile.WriteInteger('Images', 'UseNewFormat', Ord(MenuImagesNewFormat.Checked));
    INIFile.WriteInteger('Images', 'UseOldFormat', Ord(MenuImagesOldFormat.Checked));

    with FormPreferences do
    begin
      INIFile.WriteInteger('Images', 'DisplayParent', Ord(PopupImageDisplayParent.Checked));
      INIFile.WriteInteger('Images', 'ImageResampler', MenuImageResampler.Tag);
      INIFile.WriteInteger('Images', 'CycleImageTypes', Ord(CycleImageTypes.Checked));

      INIFile.WriteString('Images', 'Marquees_title', DescriptionMarquees.Text);
      INIFile.WriteString('Images', 'Flyers_title', DescriptionFlyers.Text);
      INIFile.WriteString('Images', 'Cabinets_title', DescriptionCabinets.Text);
      INIFile.WriteString('Images', 'ControlPanels_title', DescriptionControlPanels.Text);
      INIFile.WriteString('Images', 'ControlPanelLayouts_title', DescriptionControlPanelLayouts.Text);
      INIFile.WriteString('Images', 'Wallpapers_title', DescriptionWallpapers.Text);
      INIFile.WriteString('Images', 'Hardware_title', DescriptionHardware.Text);
      INIFile.WriteString('Images', 'Custom_title', DescriptionCustomImage.Text);
      INIFile.WriteInteger('Images', 'TitleSnapshots_enable', Ord(EnableTitleSnapshots.Checked));
      INIFile.WriteInteger('Images', 'Marquees_enable', Ord(EnableMarquees.Checked));
      INIFile.WriteInteger('Images', 'Flyers_enable', Ord(EnableFlyers.Checked));
      INIFile.WriteInteger('Images', 'Cabinets_enable', Ord(EnableCabinets.Checked));
      INIFile.WriteInteger('Images', 'ControlPanels_enable', Ord(EnableControlPanels.Checked));
      INIFile.WriteInteger('Images', 'ControlPanelLayouts_enable', Ord(EnableControlPanelLayouts.Checked));
      INIFile.WriteInteger('Images', 'Select_enable', Ord(EnableSelect.Checked));
      INIFile.WriteInteger('Images', 'Versus_enable', Ord(EnableVersus.Checked));
      INIFile.WriteInteger('Images', 'Wallpapers_enable', Ord(EnableWallpapers.Checked));
      INIFile.WriteInteger('Images', 'Hardware_enable', Ord(EnableHardware.Checked));
      INIFile.WriteInteger('Images', 'Custom_enable', Ord(EnableCustomImage.Checked));

      INIFile.WriteInteger('Images', 'ShowMAWSGameInfo', Ord(ButtonShowMAWSGameInfo.Checked));
    end;

    INIFile.WriteInteger('Images', 'ShowImages', Ord(MenuShowImages.Checked));
    INIFile.WriteInteger('Images', 'ImageViewMode', ButtonImagesViewMode.Tag);

    with FormPreferences do
    begin
      INIFile.WriteInteger('X-Arcade', 'UseXArcade', Ord(XArcade.Checked));
      INIFile.WriteInteger('HotRodSE', 'UseHotRodSE', Ord(HotRodSE.Checked));
      INIFile.WriteInteger('SlikStik', 'UseSlikStik', Ord(SlikStik.Checked));
      INIFile.WriteInteger('SlikStik', 'Swap2ndStick', Ord(SlikStikSwap2ndPlayerStick.Checked));
      INIFile.WriteInteger('DevastatorII', 'UseDevastatorII', Ord(Devastator2.Checked));

      INIFile.WriteString('Preferences', 'SplashLogoFile', SplashLogo.Text);

      // FMOD settings
      INIFile.WriteInteger('Audio', 'PlayAudio', Ord(PlayAudio.Checked));
      INIFile.WriteInteger('Audio', 'Volume', AudioVolume.Position);
      for Loop:= 1 to MaxArcadeSystems do
          INIFile.WriteString('Audio', 'folder_'+LowerCase(GetSystemIniSection(Loop)), AudioFolders[Loop]);
      if OutputDevice.Items.Count > 0 then
         INIFile.WriteInteger('Audio', 'OutputDevice', OutputDevice.ItemIndex)
      else
         INIFile.WriteInteger('Audio', 'OutputDevice', OutputDevice.Tag);
      INIFile.WriteInteger('Audio', 'MixerType', MixerType.ItemIndex);
      INIFile.WriteInteger('Audio', 'OutputRate', OutputRate.ItemIndex);

      INIFile.WriteInteger('Video', 'PlayMNG', Ord(PlayMNG.Checked));
      INIFile.WriteInteger('Video', 'UseParent', Ord(AudioVideoUseParent.Checked));
      INIFile.WriteInteger('Video', 'Loop', Ord(AudioVideoLoop.Checked));
      for Loop:= 1 to MaxArcadeSystems do
          INIFile.WriteString('Video', 'folder_'+LowerCase(GetSystemIniSection(Loop)), MNGFolders[Loop]);

      // Random Game Preview
      INIFile.WriteInteger('RandomGamePreview', 'WarningPanelAnimation', Ord(WarningPanelAnimation.Checked));
      INIFile.WriteInteger('RandomGamePreview', 'RestoreSelectedGame', Ord(RestoreSelectedGame.Checked));
      INIFile.WriteInteger('RandomGamePreview', 'NumberGamesToRun', NumberGamesToRun.Position);
      INIFile.WriteInteger('RandomGamePreview', 'RunningTime', GamePreviewRunningTime.Position);
      INIFile.WriteInteger('RandomGamePreview', 'UseAvailableGamesOnly', UseAvailableGamesOnly.Position);
      INIFile.WriteInteger('RandomGamePreview', 'PauseBetweenGames', PauseBetweenGames.Position);
      INIFile.WriteInteger('RandomGamePreview', 'PauseBeforeEmulatorStarts', PauseBeforeEmulatorStarts.Position);
      INIFile.WriteInteger('RandomGamePreview', 'WindowBlendFactor', BlendPreviewWindowFactor.Position);
    end;

    INIFile.WriteInteger('ToolBar', 'ToolBar_visible', ToolBarPanel.Tag);
    INIFile.WriteInteger('ToolBar', 'ViewMode_visible', Ord(ButtonViewMode.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterSystems_visible', Ord(ButtonGameFilterArcade.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterMain_visible', Ord(ButtonGameFilterMain.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterMasterClone_visible', Ord(ButtonGameFilterMasterClone.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterHaveMiss_visible', Ord(ButtonGameFilterHaveMiss.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterWorkNonWork_visible', Ord(ButtonGameFilterWorkingNonWorking.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterHideBios_visible', Ord(ButtonGameFilterHideBios.Visible));
    INIFile.WriteInteger('ToolBar', 'FilterNumberScreens', Ord(ButtonGameFilterNumberScreens.Visible));
    INIFile.WriteInteger('ToolBar', 'ImagesViewMode_visible', Ord(ButtonImagesViewMode.Visible));
    INIFile.WriteInteger('ToolBar', 'RandomGame_visible', Ord(ButtonRandomGame.Visible));

    INIFile.WriteInteger('ImagesToolBar', 'ToolBar_visible', ImagesToolBarPanel.Tag);
    INIFile.WriteInteger('ImagesToolBar', 'PreviousImage', Ord(ButtonPreviousImage.Visible));
    INIFile.WriteInteger('ImagesToolBar', 'NextImage', Ord(ButtonNextImage.Visible));
    INIFile.WriteInteger('ImagesToolBar', 'PreviousType', Ord(ButtonPreviousType.Visible));
    INIFile.WriteInteger('ImagesToolBar', 'NextType', Ord(ButtonNextType.Visible));
    INIFile.WriteInteger('ImagesToolBar', 'VisualEffects', Ord(ButtonImageVisualEffects.Visible));
    INIFile.WriteInteger('ImagesToolBar', 'ImageViewMode', Ord(ButtonImageToolBarViewMode.Visible));


    INIFile.WriteInteger('StatusBar', 'ToolBar_visible', StatusBarPanel.Tag);
    INIFile.WriteInteger('StatusBar', 'GameName_visible', Ord(StatusBar_GameName.Visible));
    INIFile.WriteInteger('StatusBar', 'GameSize_visible', Ord(StatusBar_GameSize.Visible));
    INIFile.WriteInteger('StatusBar', 'TotalEntries_visible', Ord(StatusBar_TotalEntries.Visible));
    INIFile.WriteInteger('StatusBar', 'FavoritesProfile_visible', Ord(StatusBar_FavoritesProfile.Visible));
    INIFile.WriteInteger('StatusBar', 'GameSizeFormat', MenuGameSizeFormat.Tag);

    SaveSnapFolderZipFile(1);
    SaveSnapFolderZipFile(2);
    SaveSnapFolderZipFile(3);
    SaveSnapFolderZipFile(4);
    SaveSnapFolderZipFile(5);
    SaveSnapFolderZipFile(6);

    WriteEmulatorVariables(1); // MAME
    WriteEmulatorVariables(2); // ZiNc
    WriteEmulatorVariables(3); // Daphne
    WriteEmulatorVariables(4); // AGEMAME
    WriteEmulatorVariables(5); // PinMAME
    WriteEmulatorVariables(6); // HazeMD

    INIFile.UpdateFile;
  finally
    FreeAndNil(INIFile);
  end;

  // Audit
  try
    INIFile:= TMemIniFile.Create(FrontendPath+'ini_files\el_extras.ini');
    INIFile.WriteString('Audit', 'DownloadAddress', PopupAuditDownloadAddress.Hint);
    INIFile.WriteInteger('Audit', 'NotUsedFiles', Ord(PopupAuditNotUsedFiles.Checked));
    INIFile.UpdateFile;
  finally
    FreeAndNil(INIFile);
  end;
end;

function TFormMain.CheckAllMAMEIniFiles(out ErrorString: String): Boolean;

  function AddNewLine: Boolean;
  begin
    if ErrorString <> '' then
       ErrorString:= ErrorString+#13#10;
  end;

  procedure VerifyEmu(sID: Integer);
  begin
    if (EmulatorFile[sID] <> '') and (FileExists(EmulatorFile[sID])) then
       begin
         if not CheckMAMEIniFile(EmulatorFile[sID], sID) then
            begin
              AddNewLine;
              ErrorString:= ErrorString+GetEmuFullDescription(sID)+' - [emulator.ini is missing and failed to be created].';
              Result:= False;
            end;
       end;
    if not Result then
       begin
         AddNewLine;
         ErrorString:= ErrorString+GetEmuFullDescription(sID);
       end;
  end;

begin
  Result:= True;
  ErrorString:= '';
  VerifyEmu(1);
  VerifyEmu(4);
  VerifyEmu(5);
  VerifyEmu(6);
  AddNewLine;
end;

function TFormMain.CheckMAMEIniFile(EmulatorFileName: String; SystemID: Integer): Boolean;
begin
  Result:= (EmulatorFileName <> '') and FileExists(EmulatorFileName);
  if Result then
     begin
       if not FileExists(GetMAMEIniFileName(EmulatorFileName, SystemID)) then
          CreateMAMEIniFile(EmulatorFileName);
     end;
end;

function TFormMain.GetMAMEIniFileName(EmulatorFileName: String; SystemID: Integer): String;
var
  tmpSys: String;
begin
  Result:= '';
  case SystemID of
     1: tmpSys:= 'mame.ini';
     4: tmpSys:= 'age.ini';
     5: tmpSys:= 'pinmame.ini';
     6: tmpSys:= 'hazemd.ini';
  else
     begin
       GenerateMessage('Error', 'System ID is invalid, cannot generate .ini filename.', 2);
       Exit;
     end;
  end;

  if EmulatorFileName = '' then
     begin
       GenerateMessage('Error', GetEmuFullDescription(SystemID)+#13#10+'Filename is '+
                       'empty. Please make sure that an emulator is selected for this system.', 2);
       Exit;
     end;
  case FileExists(ExtractFilePath(EmulatorFileName)+tmpSys) of
    True : Result:= ExtractFilePath(EmulatorFileName)+tmpSys;
    False: Result:= ExtractFilePath(EmulatorFileName)+ChangeFileExt(ExtractFileName(EmulatorFileName), '.ini');
  end;
end;

function TFormMain.GetMAMECustomIniFileName(EmulatorFileName, GameName: String; SystemID: Integer): String;
begin
  Result:= '';
  if EmulatorFileName = '' then
     begin
       GenerateMessage('Error', GetEmuFullDescription(SystemID)+#13#10+'Filename is '+
                       'empty. Please make sure that an emulator is selected for this system.', 2);
       Exit;
     end;
  if Pos(':', IniFilesDir[SystemID]) <> 0 then
     Result:= FormMain.IniFilesDir[SystemID]+'\'+GameName+'.ini'
       else
     Result:= ExtractFilePath(EmulatorFileName)+IniFilesDir[SystemID]+'\'+GameName+'.ini';
end;


procedure TFormMain.AddControllerDefinitionsMenuItems(EmulatorFileName: String);
var
  ctrlrKeysList: THashedStringList;
  iniFolder, SelectedDesc: String;
  Loop: Integer;
begin
  if MenuController.Count > 0 then
     begin
       for Loop:=0 to MenuController.Count-1 do
       begin
         if MenuController.Items[Loop].Checked then
            begin
              SelectedDesc:= MenuController.Items[Loop].Hint;
              Break;
            end;
       end;
     end;
  MainMenu.BeginUpdate;
  MenuController.Clear;

  AddMenuItem(MenuController, '(None)', '', False);
  AddMenuItem(MenuController, 'Standard', 'standard', False);
  if (Pos(':\', ctrlrDir) > 0) or (Pos(':', ctrlrDir) > 0) then
     iniFolder:= ctrlrDir
  else
     iniFolder:= ExtractFilePath(EmulatorFileName)+ctrlrDir;
  ctrlrKeysList:= THashedStringList.Create;
  GenerateControllerDefinitionsFilesList(iniFolder, ctrlrKeysList, True);
  if ctrlrKeysList.Count > 0 then
     for Loop:=0 to ctrlrKeysList.Count-1 do
     begin
       if LowerCase(ctrlrKeysList[Loop]) <> 'standard' then
          AddMenuItem(MenuController, ctrlrKeysList[Loop], ctrlrKeysList[Loop], True);
     end;
  MainMenu.EndUpdate;
  FreeAndNil(ctrlrKeysList);
  if SelectedDesc <> '' then
     begin
       for Loop:=0 to MenuController.Count-1 do
       begin
         if MenuController.Items[Loop].Hint = SelectedDesc then
            begin
              MenuController.Items[Loop].Checked:= True;
              Break;
            end;
       end;
     end
  else
     MenuController.Items[0].Checked:= True;
end;

procedure TFormMain.AddMenuItem(MenuHolder: TMenuItem; Description, HintName: String; Duplicate: Boolean);
var
  NewMenuItem: TMenuItem;
  Loop: Integer;
begin
  if not Duplicate then
     begin
       if MenuHolder.Count > 0 then
          begin
            for Loop:=0 to MenuHolder.Count-1 do
            begin
              if MenuHolder.Items[Loop].Caption = Description then
                 Exit;
            end;
          end;
     end;

  NewMenuItem:= TMenuItem.Create(MenuHolder);
  NewMenuItem.Caption:= Description;
  NewMenuItem.AutoCheck:= True;
  NewMenuItem.RadioItem:= True;
  NewMenuItem.Hint:= HintName;
  MenuHolder.Add(NewMenuItem);
  if HintName = 'disabled' then
     NewMenuItem.Checked:= True;
end;

function TFormMain.Get_DOSBox_Status(RunningGame: Boolean): Word;
begin
  case RunningGame of
    True:
      begin
        Result:= SW_SHOWNORMAL;
        case FormPreferences.RunEmulatorDOSBox.ItemIndex of
          0: Result:= SW_SHOWNORMAL;
          1: Result:= SW_SHOWMINIMIZED;
          2: Result:= SW_HIDE;
        end;
      end;
    False:
      begin
        Result:= SW_SHOWMINIMIZED;
        case FormPreferences.ExtractEmulatorDataDOSBox.ItemIndex of
          0: Result:= SW_SHOWMINIMIZED;
          1: Result:= SW_HIDE;
        end;
      end;
  end;
end;

procedure TFormMain.CreateMAMEIniFile(EmulatorFileName: String);
begin
  SetCurrentDir(ExtractFilePath(EmulatorFileName));
  RunProcess(WinQuotesStr+EmulatorFileName+WinQuotesStr+' -createconfig', True, Get_DOSBox_Status(False), False);
  SetCurrentDir(FrontendPath);
end;

function TFormMain.GetFolderZiNc_cfg: String;
begin
  Result:= FrontendPath+GetMachineTypeGamesFolder+'zinc_cfg\';
end;

procedure TFormMain.ReadZiNc_cfg(FileName: String; CustomGameSettings: Boolean);
var
  cfgFile, tempList: THashedStringList;
  cfgFileName, cmdString, tempStr, xResolution, yResolution: String;
  Loop, Position: Integer;

  function FixValueString(StringValue: String): String;
  begin
    Position:= Pos(';', StringValue);
    if Position <> 0 then
       Result:= Copy(StringValue, 1, Position-1);
    Result:= Trim(Result);
  end;

  procedure FillFileNames;
  begin
    FixEmptyValue(FormZiNcSettings.RendererZNC, 'renderer.znc');
    FixEmptyValue(FormZiNcSettings.RendererConfigFile, 'renderer.cfg');
    FixEmptyValue(FormZiNcSettings.ControllerZNC, 'controller.znc');
  end;

begin
  cfgFileName:= GetFolderZiNc_cfg+FileName+'.cfg';
  if not FileExists(cfgFileName) then
     begin
       FillFileNames;
       Exit;
     end;
  Position:= 0;
  cfgFile:= THashedStringList.Create;
  if FileExists(cfgFileName) then
     begin
       cfgFile.LoadFromFile(cfgFileName);
       Position:= Pos(' ', cfgFile[0]);
     end;

  if Position <> 0 then
     begin
       // one line parameters
       tempList:= THashedStringList.Create;
       tempList.BeginUpdate;
       tempStr:= '';
       cmdString:= cfgFile[0];
       for Loop:= 1 to Length(cmdString)+1 do
       begin
         if (Loop > Length(cmdString)) or (cmdString[Loop] = ' ') then
            begin
              tempList.Add(tempStr);
              tempStr:= '';
            end
         else
            tempStr:= tempStr+cmdString[Loop];
       end;
       tempList.EndUpdate;
       cfgFile.BeginUpdate;
       cfgFile.Clear;
       cfgFile.AddStrings(tempList);
       cfgFile.EndUpdate;
       FreeAndNil(tempList);
     end;
  if Assigned(emuROMsFolders[2]) then
     begin
       if emuROMsFolders[2].Text <> '' then
          FormZiNcSettings.FolderROMs.Text:= emuROMsFolders[2].Strings[0];
     end;
  for Loop:=0 to cfgFile.Count-1 do
  begin
    if cfgFile.Names[Loop] = '--use-sound' then
       FormZiNcSettings.Sound.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes'
    else
    if cfgFile.Names[Loop] = '--renderer' then
       FormZiNcSettings.RendererZNC.Text:= ShortToLongPath(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--use-renderer-cfg-file' then
       FormZiNcSettings.RendererConfigFile.Text:= ShortToLongPath(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--rotate' then
       FormZiNcSettings.Rotate.ItemIndex:= StrToInt(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--controller' then
       FormZiNcSettings.ControllerZNC.Text:= ShortToLongPath(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--use-controller-cfg-file' then
       FormZiNcSettings.ControllerConfigFile.Text:= ShortToLongPath(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--sound-filter-enable' then
       FormZiNcSettings.SoundFilter.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes'
    else
    if cfgFile.Names[Loop] = '--sound-filter-cutoff' then
       begin
         case StrToInt(cfgFile.ValueFromIndex[Loop]) of
           11025: FormZiNcSettings.SoundFilterCutoff.ItemIndex:= 0;
           22050: FormZiNcSettings.SoundFilteRCutoff.ItemIndex:= 1;
           44100: FormZiNcSettings.SoundFilteRCutoff.ItemIndex:= 2;
           48000: FormZiNcSettings.SoundFilteRCutoff.ItemIndex:= 3;
         end;
       end
    else
    if cfgFile.Names[Loop] = '--sound-surround-lite-enable' then
       FormZiNcSettings.SoundLiteSurround.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes'
    else
    if cfgFile.Names[Loop] = '--sound-surround_lite-multiplier' then
       FormZiNcSettings.SoundLiteSurroundMultiplier.Position:= StrToInt(cfgFile.ValueFromIndex[Loop])
    else
    if cfgFile.Names[Loop] = '--sound-stereo-exciter' then
       FormZiNcSettings.SoundStereoExciter.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes'
    else
    if cfgFile.Names[Loop] = '--use-slow-geometry' then
       FormZiNcSettings.SlowGeometry.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes';
    FormZiNcSettings.NetGameServer.Checked:= (cfgFile.Names[Loop] = '--netgame-server');
    //if cfgFile.Names[Loop] = '--netgame-server' then
    //   FormZiNcSettings.NetGameServer.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes';
    if cfgFile.Names[Loop] = '--netgame-connect' then
       FormZiNcSettings.NetGameConnect.Text:= cfgFile.ValueFromIndex[Loop];
    if cfgFile.Names[Loop] = '--use-mem-predict' then
       FormZiNcSettings.MemoryPrediction.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes';
    if cfgFile.Names[Loop] = '--use-stackinram-hack' then
       FormZiNcSettings.StackInRAMHack.Checked:= LowerCase(cfgFile.ValueFromIndex[Loop]) = 'yes';
  end;
  FillFileNames;
  if ValidateFile(FormZiNcSettings.RendererConfigFile.Text) then
     begin
       cfgFile.Clear;
       if Pos(':', FormZiNcSettings.RendererConfigFile.Text) = 0 then
          cfgFile.LoadFromFile(ExtractFilePath(EmulatorFile[2])+FormZiNcSettings.RendererConfigFile.Text)
       else
          cfgFile.LoadFromFile(FormZiNcSettings.RendererConfigFile.Text);
       case FormZiNcSettings.OpenGL_D3DRendererType of
         True:
           begin
             for Loop:=0 to cfgFile.Count-1 do
             begin
               if Trim(cfgFile.Names[Loop]) = 'XSize' then
                  xResolution:= FixValueString(cfgFile.ValueFromIndex[Loop])
               else
               if Trim(cfgFile.Names[Loop]) = 'YSize' then
                  yResolution:= FixValueString(cfgFile.ValueFromIndex[Loop])
               else
               if Trim(cfgFile.Names[Loop]) = 'FullScreen' then
                  FormZiNcSettings.FullScreen.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'ColorDepth' then
                  FormZiNcSettings.ColorDepth.ItemIndex:= Ord((FixValueString(cfgFile.ValueFromIndex[Loop]) = '32'))
               else
               if Trim(cfgFile.Names[Loop]) = 'ScanLines' then
                  FormZiNcSettings.Scanlines.ItemIndex:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'Filtering' then
                  FormZiNcSettings.TextureFilter.Position:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'Blending' then
                  FormZiNcSettings.Blending.ItemIndex:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'Dithering' then
                  FormZiNcSettings.Dithering.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'ShowFPS' then
                  FormZiNcSettings.ShowFPS.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'FrameLimitation' then
                  FormZiNcSettings.FrameLimitation.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'FrameSkipping' then
                  FormZiNcSettings.FrameSkip.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'FramerateDetection' then
                  FormZiNcSettings.FramerateDetection.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
               else
               if Trim(cfgFile.Names[Loop]) = 'FramerateManual' then
                  FormZiNcSettings.FramerateManual.Position:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'TextureType' then
                  FormZiNcSettings.TextureType.ItemIndex:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'TextureType' then
                  FormZiNcSettings.TextureCache.Position:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
               else
               if Trim(cfgFile.Names[Loop]) = 'TurnDisplay' then
                  FormZiNcSettings.TurnDisplay.Position:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]));
             end;
             if (xResolution <> '') and (yResolution <> '') then
                begin
                  tempStr:= xResolution+'x'+yResolution;
                  FormZiNcSettings.Resolution.ItemIndex:= FormZiNcSettings.Resolution.Items.IndexOf(tempStr);
                  if FormZiNcSettings.Resolution.ItemIndex = -1 then
                     FormZiNcSettings.Resolution.ItemIndex:= 2;
                end;
           end;
         False:
           begin
             if Trim(cfgFile.Names[Loop]) = 'Resolution' then
                FormZiNcSettings.Glide_Resolution.ItemIndex:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
             else
             if Trim(cfgFile.Names[Loop]) = 'Filtering' then
                FormZiNcSettings.Glide_TextureFilter.ItemIndex:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
             else
             if Trim(cfgFile.Names[Loop]) = 'ShowFPS' then
                FormZiNcSettings.Glide_ShowFPS.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
             else
             if Trim(cfgFile.Names[Loop]) = 'FrameLimitation' then
                FormZiNcSettings.Glide_FrameLimitation.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
             else
             if Trim(cfgFile.Names[Loop]) = 'FrameSkipping' then
                FormZiNcSettings.Glide_FrameSkip.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
             else
             if Trim(cfgFile.Names[Loop]) = 'FramerateDetection' then
                FormZiNcSettings.Glide_FramerateDetection.Checked:= Boolean(StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop])))
             else
             if Trim(cfgFile.Names[Loop]) = 'FramerateManual' then
                FormZiNcSettings.Glide_FramerateManual.Position:= StrToInt(FixValueString(cfgFile.ValueFromIndex[Loop]))
             else
           end;
       end;
     end;
  FreeAndNil(cfgFile);
end;

procedure TFormMain.UpdateZiNc_cfg(FileName: String; CustomGameSettings: Boolean);
var
  cfgFile: THashedStringList;
  elCFG: TMemIniFile;
  cfgFileName, cmdString, xResolution, yResolution: String;
  Position: Integer;

  function WriteRendererLine(Entry, Value, Comment: String): String;
  begin
    Result:= Format('%-24s= %-6s; %s', [Entry, Value, Comment]);
  end;

  procedure AddSetting(SettingString: String);
  begin
    case FormPreferences.ZiNc_BreakSettingsCFG.Checked of
      True: cfgFile.Add(SettingString);
      False:
        begin
          if cmdString = '' then
             cmdString:= SettingString
          else
             cmdString:= cmdString+' '+SettingString;
        end;
    end;
  end;

begin
  cfgFileName:= GetFolderZiNc_cfg+FileName+'.cfg';
  ForceDirectories(GetFolderZiNc_cfg);
  cfgFile:= THashedStringList.Create;
  cfgFile.BeginUpdate;
  cfgFile.Clear;
  cmdString:= '';
  if FormZiNcSettings.FolderROMs.Text <> '' then
     begin
       if not Assigned(emuROMsFolders[2]) then
          emuROMsFolders[2]:= THashedStringList.Create;
       emuROMsFolders[2].BeginUpdate;
       emuROMsFolders[2].Clear;
       emuROMsFolders[2].Add(FormZiNcSettings.FolderROMs.Text);
       emuROMsFolders[2].EndUpdate;
       //AddSetting('--roms-directory='+LongToShortPath(FormZiNcSettings.FolderROMs.Text));
     end
  else
     FreeAndNil(emuROMsFolders[2]);

  try
    elCFG:= TMemIniFile.Create(FrontendPath+'EmuLoader.ini');
    case Assigned(emuROMsFolders[2]) of
      True : elCFG.WriteString(GetSystemIniSection(2), 'roms_path', emuROMsFolders[2].Strings[0]);
      False: elCFG.DeleteKey(GetSystemIniSection(2), 'roms_path');
    end;
    elCFG.UpdateFile;
  finally
    FreeAndNil(elCFG);
  end;

  if not FormZiNcSettings.Sound.Checked then
     AddSetting('--use-sound=no');

  if (FormZiNcSettings.RendererZNC.Text <> '') and (LowerCase(FormZiNcSettings.RendererZNC.Text) <> 'renderer.znc') then
     AddSetting('--renderer='+LongToShortPath(FormZiNcSettings.RendererZNC.Text));

  if (FormZiNcSettings.RendererConfigFile.Text <> '') and (LowerCase(FormZiNcSettings.RendererConfigFile.Text) <> 'renderer.cfg') then
     AddSetting('--use-renderer-cfg-file='+LongToShortPath(FormZiNcSettings.RendererConfigFile.Text));

  if FormZiNcSettings.Rotate.ItemIndex > 0 then
     AddSetting('--rotate='+IntToStr(FormZiNcSettings.Rotate.ItemIndex));

  if (FormZiNcSettings.ControllerZNC.Text <> '') and (LowerCase(FormZiNcSettings.ControllerZNC.Text) <> 'controller.znc') then
     AddSetting('--controller='+LongToShortPath(FormZiNcSettings.ControllerZNC.Text));

  if FormZiNcSettings.ControllerConfigFile.Text <> '' then
     AddSetting('--use-controller-cfg-file='+LongToShortPath(FormZiNcSettings.ControllerConfigFile.Text));

  if FormZiNcSettings.SoundFilter.Checked then
     AddSetting('--sound-filter-enable=yes');

  if FormZiNcSettings.SoundFilteRCutoff.Text <> '22050 Hz' then
     AddSetting('--sound-filter-cutoff='+Copy(FormZiNcSettings.SoundFilteRCutoff.Text, 1, (Pos(' ', FormZiNcSettings.SoundFilteRCutoff.Text)-1)));

  if FormZiNcSettings.SoundLiteSurround.Checked then
     AddSetting('--sound-surround-lite-enable=yes');

  if FormZiNcSettings.SoundLiteSurroundMultiplier.Position <> 40 then
     AddSetting('--sound-surround_lite-multiplier='+IntToStr(FormZiNcSettings.SoundLiteSurroundMultiplier.Position));

  if FormZiNcSettings.SoundStereoExciter.Checked then
     AddSetting('--sound-stereo-exciter=yes');

  if FormZiNcSettings.SlowGeometry.Checked then
     AddSetting('--use-slow-geometry=yes');

  if FormZiNcSettings.NetGameServer.Checked then
     AddSetting('--netgame-server');

  if FormZiNcSettings.NetGameConnect.Text <> '' then
     AddSetting('--netgame-connect='+FormZiNcSettings.NetGameConnect.Text);

  if FormZiNcSettings.MemoryPrediction.Checked then
     AddSetting('--use-mem-predict');

  if FormZiNcSettings.StackInRAMHack.Checked then
     AddSetting('--use-stackinram-hack');

  if not FormPreferences.ZiNc_BreakSettingsCFG.Checked then
     cfgFile.Add(cmdString);
  cfgFile.EndUpdate;
  try
    cfgFile.SaveToFile(cfgFileName);
  finally
  end;
  cfgFile.Clear;
  case FormZiNcSettings.OpenGL_D3DRendererType of
    True: // OpenGL / Direct 3D
      begin
        cfgFile.Add('; renderer settings');
        cfgFile.Add('');
        Position:= Pos('x', FormZiNcSettings.Resolution.Text);
        xResolution:= Copy(FormZiNcSettings.Resolution.Text, 1, Position-1);
        yResolution:= Copy(FormZiNcSettings.Resolution.Text, Position+1, Length(FormZiNcSettings.Resolution.Text)-Position);
        cfgFile.Add(WriteRendererLine('XSize', xResolution, 'window/fullscreen X size'));
        cfgFile.Add(WriteRendererLine('YSize', yResolution, 'window/fullscreen Y size'));
        cfgFile.Add(WriteRendererLine('FullScreen', IntToStr(Ord(FormZiNcSettings.FullScreen.Checked)), 'Fullscreen mode: 0/1'));
        case FormZiNcSettings.ColorDepth.ItemIndex of
          0: cfgFile.Add(WriteRendererLine('ColorDepth', '16', 'Fullscreen color depth: 16/32'));
          1: cfgFile.Add(WriteRendererLine('ColorDepth', '32', 'Fullscreen color depth: 16/32'));
        end;
        cfgFile.Add(WriteRendererLine('ScanLines', IntToStr(FormZiNcSettings.Scanlines.ItemIndex), 'Scannlines: 0=none, 1=black, 2=bright'));
        cfgFile.Add(WriteRendererLine('Filtering', IntToStr(FormZiNcSettings.TextureFilter.Position), 'Texture filtering: 0-3'));
        cfgFile.Add(WriteRendererLine('Blending', IntToStr(FormZiNcSettings.Blending.ItemIndex), 'Enhanced color blend: ogl: 0/1; D3D: 0-2'));
        cfgFile.Add(WriteRendererLine('Dithering', IntToStr(Ord(FormZiNcSettings.Dithering.Checked)), 'Dithering: 0/1'));
        cfgFile.Add(WriteRendererLine('ShowFPS', IntToStr(Ord(FormZiNcSettings.ShowFPS.Checked)), 'FPS display on startup: 0/1'));
        cfgFile.Add(WriteRendererLine('FrameLimitation', IntToStr(Ord(FormZiNcSettings.FrameLimitation.Checked)), 'Frame limit: 0/1'));
        cfgFile.Add(WriteRendererLine('FrameSkipping', IntToStr(Ord(FormZiNcSettings.FrameSkip.Checked)), 'Frame skip: 0/1'));
        cfgFile.Add(WriteRendererLine('FramerateDetection', IntToStr(Ord(FormZiNcSettings.FramerateDetection.Checked)), 'Auto framerate detection: 0/1'));
        cfgFile.Add(WriteRendererLine('FramerateManual', IntToStr(FormZiNcSettings.FramerateManual.Position), 'Manual framerate: 0-1000'));
        cfgFile.Add(WriteRendererLine('TextureType', IntToStr(FormZiNcSettings.TextureType.ItemIndex), 'Textures: 0=default, 1=4 bit, 2=5bit, 3=8bit'));
        cfgFile.Add(WriteRendererLine('TextureCaching', IntToStr(FormZiNcSettings.TextureCache.Position), 'Caching type: 0-2'));
        cfgFile.Add(WriteRendererLine('TurnDisplay', IntToStr(FormZiNcSettings.TurnDisplay.Position), 'Turn the whole display (0-2, 0=default)'));
        if Pos(':', FormZiNcSettings.RendererConfigFile.Text) = 0 then
           cfgFileName:= ExtractFilePath(EmulatorFile[2])+FormZiNcSettings.RendererConfigFile.Text
        else
           cfgFileName:= FormZiNcSettings.RendererConfigFile.Text;
        try
          cfgFile.SaveToFile(cfgFileName);
        finally
        end;
      end;
    False: // 3Dfx Glide
      begin
        cfgFile.Add('; WinZiNc Glide Renderer settings');
        cfgFile.Add('');
        cfgFile.Add(WriteRendererLine('Resolution', IntToStr(FormZiNcSettings.Glide_Resolution.ItemIndex), 'Screen Size - see readme'));
        cfgFile.Add(WriteRendererLine('Filtering', IntToStr(FormZiNcSettings.Glide_TextureFilter.ItemIndex), 'Texture filtering: 0-2 - see readme'));
        cfgFile.Add(WriteRendererLine('ShowFPS', IntToStr(Ord(FormZiNcSettings.Glide_ShowFPS.Checked)), 'FPS display on startup: 0/1'));
        cfgFile.Add(WriteRendererLine('FrameLimitation', IntToStr(Ord(FormZiNcSettings.FrameLimitation.Checked)), 'Frame limit: 0/1'));
        cfgFile.Add(WriteRendererLine('FrameSkipping', IntToStr(Ord(FormZiNcSettings.FrameSkip.Checked)), 'Frame skip: 0/1'));
        cfgFile.Add(WriteRendererLine('FramerateDetection', IntToStr(Ord(FormZiNcSettings.FramerateDetection.Checked)), 'Auto framerate detection: 0/1'));
        cfgFile.Add(WriteRendererLine('FramerateManual', IntToStr(FormZiNcSettings.FramerateManual.Position), 'Manual framerate in Hz: 1-255'));
      end;
  end;
  if FormZiNcSettings.RendererConfigFile.Text <> '' then
     begin
       if Pos(':', FormZiNcSettings.RendererConfigFile.Text) = 0 then
          cfgFileName:= ExtractFilePath(EmulatorFile[2])+FormZiNcSettings.RendererConfigFile.Text
       else
          cfgFileName:= FormZiNcSettings.RendererConfigFile.Text;
       try
         cfgFile.SaveToFile(cfgFileName);
       finally
       end;
     end;
  FreeAndNil(cfgFile);
end;

function TFormMain.GameIsClone(const CloneName: String): Boolean;
begin
  Result:= CloneName <> '';
end;

procedure TFormMain.ExecuteGame(RunMode: ShortInt);
var
  CommandLine, NewOption, NewOption2, PathLine, SystemString: String;
  UseCustomCommandLine: Boolean;
  StartClock, StopClock: Int64;
  PathList: THashedStringList;
  Index, ControllerLoop: Integer;
  BiosSetFile: TMemIniFile;

  function AddPath(PathVariable: String): Boolean;
  begin
    Result:= (PathVariable <> '') and (PathVariable <> 'Not Found') and
             (PathList.IndexOf(PathVariable) = -1);
    if Result then
       PathList.Add(PathVariable);
  end;

  function MountPathCmd: Boolean;
  begin
    Result:= PathList.Count > 0;
    if Result then
       begin
         case SystemID_Number of
           2: PathLine:= ' --roms-directory='+PathList[0]; // ZiNc
         end;
       end;
  end;

  function GetDriverSystemCustomCmd(IsDriver: Boolean): String;
  var
    sFile: String;
  begin
    Result:= '';
    case IsDriver of
      True : sFile:= ChangeFileExt(GameInfoData.eDriverName, '');
      False: sFile:= SystemString;
    end;
    if FileExists(FrontendPath+'ini_files\cmdline\'+SystemString+sFile+'.ini') then
       Result:= sFile;
  end;

  function ResetSettings: Boolean;
  begin
    Result:= True;
    SetCurrentDir(FrontendPath);
    if not Application.Active then
       Application.BringToFront;
    FocusGamesList;
  end;

begin
  // modes
  //  0 -> normal
  //  1 -> zinc custom
  //  2 -> custom command Line
  // 10 -> custom options by default (pressing ENTER)

  UseCustomCommandLine:= False;
  GetSystemID(GameInfoData.eROMIdentification);
  Screen.Cursor:= crHourGlass;
  SystemString:= GetSystemFolderName(GameInfoData.eROMIdentification)+'\';

  if RunMode in [2, 10] then // custom command line
     begin
       NewOption:= '';
       // need to change this
       // first check gamename
       // not found ? check drivername
       // not found ? check system
       if FileExists(FrontendPath+'ini_files\cmdline\'+SystemString+GameInfoData.eName+'.ini') then
          begin
            NewOption:= ReadCustomCommandLine(GameInfoData.eName, GameInfoData.eROMIdentification, True);
            if NewOption <> '' then
               begin
                 CommandLine:= NewOption;
                 UseCustomCommandLine:= True;
               end;
          end;
       if not UseCustomCommandLine then
          begin
            // check game driver custom cmdline
            NewOption:= '';
            NewOption2:= GetDriverSystemCustomCmd(True);
            if NewOption2 <> '' then
               begin
                 NewOption:= ReadCustomCommandLine(NewOption2, GameInfoData.eROMIdentification, True);
                 if NewOption <> '' then
                    begin
                      CommandLine:= NewOption;
                      UseCustomCommandLine:= True;
                    end;
               end;
          end;

       if not UseCustomCommandLine then
          begin
            // check system custom cmdline
            NewOption:= '';
            NewOption2:= GetDriverSystemCustomCmd(False);
            if NewOption2 <> '' then
               begin
                 NewOption:= ReadCustomCommandLine(NewOption2, GameInfoData.eROMIdentification, True);
                 if NewOption <> '' then
                    begin
                      CommandLine:= NewOption;
                      UseCustomCommandLine:= True;
                    end;
               end;
          end;
       //if UseCustomCommandLine then
       //  begin
       //     if Pos('%s', LowerCase(NewOption)) <> 0 then
       //        CommandLine:= Format(NewOption, [GameInfoData.eName]);
       //   end;
     end;

  if (not UseCustomCommandLine) then
     begin
       if ((RunMode <> 0) and // not normal/standard
          (SystemID_Number in [1, 3, 4, 5, 6])) and
          (RunMode <> 10) then
          begin
            if RunMode = 2 then
               GenerateMessage('Error', 'There is no custom command line to execute. Aborting...', 2);
            SetCurrentDir(FrontendPath);
            Exit;
          end;
       if SystemID_Number in [1, 4, 5, 6] then
          begin
            if not Check_ROMsData_File(SystemID_Number) then
               Exit;
          end;

       case FileExists(EmulatorFile[SystemID_Number]) of
         True:
           begin
             CommandLine:= WinQuotesStr+EmulatorFile[SystemID_Number]+WinQuotesStr+' ';

             case SystemID_Number of
               1, 3, 4, 5, 6:
                  CommandLine:= CommandLine+GameInfoData.eName;
               2: CommandLine:= CommandLine+GameInfoData.eMerged;
             end;
           end;
         False:
           begin
              GenerateMessage('File Not Found', GetEmuFullDescription(SystemID_Number)+#13#10+
                              'Emulator not found. Aborted...', 2);
              Exit;
           end;
       end;
       PathList:= THashedStringList.Create;
       PathList.BeginUpdate;
       case SystemID_Number of
         1, 4, 5, 6: // MAME, AGEMAME, PinMAME, HazeMD
           begin
             if MenuPlayRecordedGame.Checked then
                begin
                  case MenuMAMESelectInputFile.Checked of
                    False: NewOption:= GameInfoData.eName;
                    True : NewOption:= GetInputFileName;
                  end;
                  if NewOption <> '' then
                     CommandLine:= CommandLine+' -playback '+NewOption;
                end
             else
             if MenuRecordGame.Checked then
                begin
                  case MenuMAMESelectInputFile.Checked of
                    False: NewOption:= GameInfoData.eName;
                    True : NewOption:= GetInputFileName(True);
                  end;
                  if NewOption <> '' then
                     CommandLine:= CommandLine+' -record '+NewOption;
               end;

             if (MenuController.Count > 0) and (not MenuController.Items[0].Checked) then
                for ControllerLoop:=0 to MenuController.Count-1 do
                begin
                  if MenuController.Items[ControllerLoop].Checked then
                     begin
                       CommandLine:= CommandLine+' -ctrlr '+MenuController.Items[ControllerLoop].Hint;
                       Break;
                     end;
                end;

             if MenuBiosSetUserDefined.Checked then
                begin
                  if GameInfoData.eBiosName <> '' then
                     begin
                       if FileExists(FrontendPath+'ini_files\biosset.ini') then
                          begin
                            BiosSetFile:= TMemIniFile.Create(FrontendPath+'ini_files\biosset.ini');
                            if BiosSetFile.SectionExists(GameInfoData.eBiosName) then
                               begin
                                  NewOption:= BiosSetFile.ReadString(GameInfoData.eBiosName, 'selected_bios', '');
                                  if NewOption <> '' then
                                     begin
                                       if NewOption <> BiosSetFile.ReadString(GameInfoData.eName, 'default_bios', '') then
                                          CommandLine:= CommandLine+' -bios '+NewOption;
                                     end;
                                  FreeAndNil(BiosSetFile);
                               end;
                          end;
                     end;
                end;
             if MenuMAMELoadSaveState.Checked then
               begin
                 NewOption:= GetSaveStateFileName;
                 if NewOption <> '' then
                    CommandLine:= CommandLine+' -noautosave -state '+NewOption;
               end;

             if MenuRecordMAMEAudio.Checked then
                begin
                  if AudioFolders[SystemID_Number] = '' then
                     GenerateMessage('Warning', GetEmuFullDescription(SystemID_Number)+#13#10+
                                     'Folder to record audio files is not defined! Please enter a valid folder '+
                                     'on preferences screen, "Folder /Files" tab', 2)
                  else
                     begin
                       NewOption:= IncludeTrailingPathDelimiter(FullEmuFolderFix(AudioFolders[SystemID_Number], SystemID_Number));
                       if not DirectoryExists(NewOption) then
                          ForceDirectories(NewOption);
                       NewOption2:= GameInfoData.eName+'.wav';
                       if FileExists(NewOption+NewOption2) then
                          begin
                            Index:= 0;
                            NewOption2:= Format('%s%.4u.wav', [GameInfoData.eName, Index]);
                            repeat
                              NewOption2:= Format('%s%.4u.wav', [GameInfoData.eName, Index]);
                              Inc(Index);
                            until (not FileExists(NewOption+NewOption2) or (Index = 9999));
                          end;
                       CommandLine:= CommandLine+Format(' -wavwrite "%s"', [NewOption+NewOption2]);
                     end;
                end;

             if MenuRecordMAMEVideo.Checked then
                begin
                  NewOption:= GetZipFolderFull(1, SystemID_Number);
                  //if MNGFolders[SystemID_Number] = '' then
                  if NewOption = '' then
                     GenerateMessage('Warning', GetEmuFullDescription(SystemID_Number)+#13#10+'Folder to record mng files is '+
                                     'not defined! You need to select a snapshot folder on preferences screen, '+
                                     '"Folder / Files" tab, "Images" sub-tab', 2)
                  else
                     begin

                       //NewOption:= IncludeTrailingPathDelimiter(FullEmuFolderFix(MNGFolders[SystemID_Number], SystemID_Number));

                       //if not DirectoryExists(NewOption) then
                       //   ForceDirectories(NewOption);
                       NewOption2:= GameInfoData.eName+'.mng';
                       if FileExists(NewOption+NewOption2) then
                          begin
                            Index:= 0;
                            NewOption2:= Format('%s%.4u.mng', [GameInfoData.eName, Index]);
                            repeat
                              NewOption2:= Format('%s%.4u.mng', [GameInfoData.eName, Index]);
                              Inc(Index);
                            until (not FileExists(NewOption+NewOption2) or (Index = 9999));
                          end;
                       CommandLine:= CommandLine+Format(' -mngwrite "%s"', [NewOption2]);
                     end;
                end;
           end;
         2: // ZiNc
           begin
             case RunMode of
               0: // standard
                 begin
                   CommandLine:= CommandLine+' --use-config-file='+
                                 LongToShortPath(GetFolderZiNc_cfg+'zinc_el.cfg');
                 end;
               1, 10: // zinc custom or run custom options by default
                 begin
                   case FileExists(GetFolderZiNc_cfg+GameInfoData.eName+'.cfg') of
                     True: CommandLine:= CommandLine+' --use-config-file='+
                                         LongToShortPath(GetFolderZiNc_cfg+GameInfoData.eName+'.cfg');
                     False:
                       begin
                         case FileExists(GetFolderZiNc_cfg+ChangeFileExt(GameInfoData.eDriverName, '.cfg')) of
                           True : CommandLine:= CommandLine+' --use-config-file='+
                                  LongToShortPath(GetFolderZiNc_cfg+ChangeFileExt(GameInfoData.eDriverName, '.cfg'));
                           False:
                                  CommandLine:= CommandLine+' --use-config-file='+
                                  LongToShortPath(GetFolderZiNc_cfg+'zinc_el.cfg');
                         end;
                       end;
                   end;
                 end;
             end;
             // search sub-folders
             // remove this ? pointless since ZiNc only support 1 ROMs folder :(
             NewOption:= '';
             NewOption:= ExcludeTrailingPathDelimiter(LongToShortPath(ExtractFilePath(SearchZIPFolder(GameInfoData.eName, GameInfoData.eROMIdentification))));
             if (NewOption = '') and (GameIsClone(GameInfoData.eClone)) then
                begin
                  NewOption:= '';
                  NewOption:= ExcludeTrailingPathDelimiter(LongToShortPath(ExtractFilePath(SearchZIPFolder(GameInfoData.eClone, GameInfoData.eROMIdentification))));
                end;
             if NewOption <> '' then
                AddPath(NewOption);
             if MountPathCmd then
                CommandLine:= CommandLine+PathLine;
             // emd of sub-folders scanning
           end;
         3: // Daphne
           begin
             CommandLine:= CommandLine+' vldp -framefile framefile\'+GameInfoData.eName+'.txt';
             if MenuDaphneRunFullScreen.Checked then
                CommandLine:= CommandLine+' -fullscreen';
             if FormPreferences.Daphne_NoLog.Checked then
                CommandLine:= CommandLine+' -nolog';
           end;
       end;
       SetCurrentDir(ExtractFilePath(EmulatorFile[SystemID_Number]));
       FreeAndNil(PathList);
     end;

  // need to check the correct MAME binary and also check all other emulators!!!
  Screen.Cursor:= crDefault;
  if CommandLine <> '' then
    begin
      // SHGetFileInfo() // to extract file type
      // this might be needed to DOS files
      {if BinaryType = etDOS then
         begin
           case Win32Platform of
             0,1: CommandLine:= 'command.com /c '+CommandLine; //Win9x
             2  : CommandLine:= 'cmd.exe /c '+SystemStr+CommandLine+SystemStr; // WinXP
           end;
         end;}

      if FormPreferences.PlayAudio.Checked then
         begin
           if FSongs[0].Playing then
              StopSound;
         end;

      if MenuViewEmulatorFullCommandLine.Checked then
         begin
           if GenerateMessage('Command Line', CommandLine+#13#10#13#10+
                              Format('Do you want load "%s" ?', [GameInfoData.eDescription]), 1) = mrNo then
              begin
                ResetSettings;
                Exit;
              end;
         end;

      if FormPreferences.EnableGamePlayTime_Played.Checked then
         StartClock:= GetTickCount;
      if FormPreferences.MinimizeFrontendToRunGames.Checked then
         MinimizeToTray;
      RunProcess(CommandLine, True, Get_DOSBox_Status(True));
      if FormPreferences.MinimizeFrontendToRunGames.Checked then
         RestoreFromTray;
      if FormPreferences.EnableGamePlayTime_Played.Checked then
         begin
           StopClock:= GetTickCount;
           UpdateSelectedGamePlayTime(GameInfoData.eROMIdentification, GameInfoData.eName, (StopClock-StartClock));
         end;
      ThousandSeparator:= Char(',');
      DecimalSeparator:= Char('.');

      if NoScreenshotLoaded then
         begin
           NoScreenshotLoaded:= False;
           MenuShowImages.OnClick(Self);
         end;
    end
  else
    GenerateMessage('Error', 'There is nothing to execute... command line is empty!', 2);
  ThousandSeparator:= Char(',');
  DecimalSeparator:= Char('.');
  ResetSettings;
end;

procedure TFormMain.SetDescriptionFormat;
var
  GameDescription: String;
  Node: PVirtualNode;
  Data: pGameInfo;

  procedure SetFormat(NewFormat: Boolean);
  begin
    case NewFormat of
      True:
        begin
          if (Copy(GameDescription, 1, 4) = 'The ') then
             GameDescription:= Copy(GameDescription, 5, Length(GameDescription))+', The'
          else
          if (Copy(GameDescription, 1, 3) = 'Le ') then
             GameDescription:= Copy(GameDescription, 4, Length(GameDescription))+', Le';
        end;
      False:
        begin
          if Pos(', The', GameDescription) > 0 then
             GameDescription:= 'The '+Copy(GameDescription, 1, Length(GameDescription)-5)
          else
          if Pos(', Le',GameDescription) > 0 then
             GameDescription:= 'Le '+Copy(GameDescription, 1, Length(GameDescription)-4);
        end;
    end;
  end;

begin
  if not CheckTotal(GamesTreeView) then
     Exit;

  GamesTreeView.BeginUpdate;
  Node:= GamesTreeView.GetFirst;
  repeat
    Data:= GamesTreeView.GetNodeData(Node);
    GameDescription:= Data.eDescription;
    SetFormat(FormPreferences.NewDescriptionFormat.Checked);
    if GameDescription <> Data.eDescription then
       Data.eDescription:= GameDescription;
    Node:= GamesTreeView.GetNext(Node);
  until (not Assigned(Node));
  GamesTreeView.EndUpdate;

  SortColumn(False);
end;

function TFormMain.FillGamePlayTime: Boolean;
begin
  mPlayTime:= '';
  mPlayed:= 0;
  if Assigned(GamePlayTime) then
     begin
       mPlayTime:= GamePlayTime.ReadString(mName, GetSystemFolderName(mROMIdentification)+'_time', '');
       mPlayed:= GamePlayTime.ReadInteger(mName, GetSystemFolderName(mROMIdentification)+'_played', 0);
     end;
end;

procedure TFormMain.SetGamePlayTime_Played;
var
  Node: PVirtualNode;
  Data: pGameInfo;

begin
  if not CheckTotal(GamesTreeView) then
     Exit;
  case FormPreferences.EnableGamePlayTime_Played.Checked of
    True:
      begin
        if (not Assigned(GamePlayTime)) and (FileExists(FrontendPath+'ini_files\gameplaytime.ini')) then
           GamePlayTime:= TMemIniFile.Create(FrontendPath+'ini_files\gameplaytime.ini');
      end;
    False:
      begin
        FreeAndNil(GamePlayTime);
      end;
  end;

  mPlayTime:= '';
  mPlayed:= 0;
  GamesTreeView.BeginUpdate;
  Node:= GamesTreeView.GetFirst;
  repeat
    Data:= GamesTreeView.GetNodeData(Node);
    mROMIdentification:= Data.eROMIdentification;
    mName:= Data.eName;
    if FormPreferences.EnableGamePlayTime_Played.Checked then
       FillGamePlayTime;

    if mPlayTime <> '' then
       begin
         Data.ePlayTimeInteger:= StrToInt64(mPlayTime);
         Data.ePlayTime:= GetPlayTime(StrToInt64(mPlayTime), True, False);
       end
    else
       begin
         Data.ePlayTimeInteger:= 0;
         Data.ePlayTime:= mPlayTime;
       end;
    Data.ePlayed:= mPlayed;

    Node:= GamesTreeView.GetNext(Node);
  until (not Assigned(Node));
  GamesTreeView.EndUpdate;
end;

function TFormMain.FullFolderFix(const FolderString: String): String;
begin
  Result:= '';
  if FolderString <> '' then
     begin
       if Pos(':', FolderString) <> 0 then
          Result:= FolderString
       else
          Result:= FrontendPath+FolderString;
     end;
end;

function TFormMain.FullEmuFolderFix(const FolderString: String; SysID: Integer): String;
begin
  Result:= '';
  if FolderString <> '' then
     begin
       if Pos(':', FolderString) <> 0 then
          Result:= FolderString
       else
          Result:= ExtractFilePath(EmulatorFile[SysID])+FolderString;
     end;
end;

function TFormMain.GetSystemFolderName(romID: Integer): String;
begin
  case romID of
    // arcade
    00..05: Result:= 'mame';
    06..09: Result:= 'zinc';
    10..13: Result:= 'daphne';
    14..19: Result:= 'agemame';
    20..25: Result:= 'pinmame';
    26..29: Result:= 'hazemd';
        32: Result:= 'customgame';
  end;
end;

function TFormMain.GetEmuFullDescription(SystemID: Integer): String;
begin
  case SystemID of
    0: Result:= 'All Systems';
    1: Result:= 'MAME - Multiple Arcade Machine Emulator';
    2: Result:= 'ZiNc - 3D Arcade Emulator';
    3: Result:= 'Daphne - A Laserdisc Arcade Game Emulator';
    4: Result:= 'AGEMAME - Arcade Gambling Extension for MAME';
    5: Result:= 'PinMAME - Pinball Multiple Arcade Machine Emulator';
    6: Result:= 'HazeMD - Haze Megadrive Emulator';
  else
       Result:= '';
  end;
end;

function TFormMain.GetSystemID(romID: Integer): Integer;
begin
  case romID of
        -1: SystemID_Number:= -1; // Unknown, error
    00..05: SystemID_Number:= 1; // MAME
    06..09: SystemID_Number:= 2; // ZiNc
    10..13: SystemID_Number:= 3; // Daphne
    14..19: SystemID_Number:= 4; // AGEMAME
    20..25: SystemID_Number:= 5; // PinMAME
    26..29: SystemID_Number:= 6; // HazeMD
  else
     SystemID_Number:= -1;
  end;
  Result:= SystemID_Number;
end;

function TFormMain.GetSystemIniSection(const SystemID: Integer): String;
begin
  case SystemID of
    1: Result:= 'MAME';
    2: Result:= 'ZiNc';
    3: Result:= 'Daphne';
    4: Result:= 'AGEMAME';
    5: Result:= 'PinMAME';
    6: Result:= 'HazeMD';
  end;
end;

function TFormMain.FillEmuDescriptionsSelector(const ComboBoxExHolder: TComboBoxEx): Boolean;
var
  Loop: ShortInt;
  emuDescription: String;
begin
  ComboBoxExHolder.ItemsEx.BeginUpdate;
  for Loop:=0 to ComboBoxExHolder.ItemsEx.Count-1 do
  begin
    emuDescription:= GetEmuFullDescription(ComboBoxExHolder.ItemsEx[Loop].ImageIndex);
    ComboBoxExHolder.ItemsEx[Loop].Caption:= emuDescription;
    if ComboBoxExHolder.ItemsEx[Loop].Caption <> emuDescription then
       ComboBoxExHolder.ItemsEx[Loop].Caption:= emuDescription;
  end;
  ComboBoxExHolder.ItemsEx.EndUpdate;
end;

procedure TFormMain.SetAlphaBlendTreeView(TreeViewHolder: TVirtualStringTree);
begin
  TreeViewHolder.SelectionBlendFactor:= GamesTreeView.SelectionBlendFactor;
  if toUseBlendedSelection in GamesTreeView.TreeOptions.PaintOptions then
     TreeViewHolder.TreeOptions.PaintOptions:= TreeViewHolder.TreeOptions.PaintOptions + [toUseBlendedSelection]
  else
     TreeViewHolder.TreeOptions.PaintOptions:= TreeViewHolder.TreeOptions.PaintOptions - [toUseBlendedSelection];
end;

function TFormMain.VerifyMultiSelect: Boolean;
begin
  Result:= GamesTreeView.SelectedCount > 1;
end;

function TFormMain.GetFavoriteUserFileName(UserName: String): String;
var
  favIni: TMemIniFile;
begin
  Result:= '';
  if UserName = 'Default' then
     Result:= 'default.el'
  else
     begin
       if FileExists(FrontendPath+'ini_files\favorites.ini') then
          begin
            favIni:= TMemIniFile.Create(FrontendPath+'ini_files\favorites.ini');
            Result:= favIni.ReadString(FavoriteUser, 'File', '');
            FreeAndNil(favIni);
          end;
     end;
end;

function TFormMain.GetFavoritesFolder: String;
begin
  Result:= FrontendPath+'ini_files\favorites\';
end;

function TFormMain.GetColumnsProfileFolder: String;
begin
  Result:= FrontendPath+'ini_files\columns\';
end;

function TFormMain.AddToFavorite: Boolean;
var
  AddToList: Boolean;
  favSystem: String;

  NotAddedGames, GamesToAdd, GamesDescription: THashedStringList;
  Loop: Integer;
  SelNode: PVirtualNode;
  MultiSelectStr, plSystem: String;

  function VerifyGame: Boolean;
  begin
    if GetGameData(SelNode) then
       begin
         plSystem:= GetSystemFolderName(GameInfoData.eROMIdentification);
         if FavList.IndexOf(GameInfoData.eName+'='+plSystem) = -1 then
            begin
              GamesToAdd.Add(Format('%s=%s', [GameInfoData.eName, plsystem]));
              GamesDescription.Add(GameInfoData.eDescription);
            end
         else
            NotAddedGames.Add(Format('%s - [%s, %s]', [GameInfoData.eDescription, GameInfoData.eName, plSystem]));
       end
    else
       GenerateMessage('Error', 'Atempt to extract name and description information from games list has failed...', 2);
  end;

begin
  Result:= False;
  if not CheckSelected(GamesTreeView) then
     Exit;
  if FavoriteUserFile = '' then
     FavoriteUserFile:= GetFavoriteUserFileName(FavoriteUser);
  if CheckReadOnly(GetFavoritesFolder+FavoriteUserFile) then
     Exit;
  Screen.Cursor:= crHourGlass;
  AddToList:= True;
  FavList:= THashedStringList.Create;
  if ValidateFile(GetFavoritesFolder+FavoriteUserFile) then
     FavList.LoadFromFile(GetFavoritesFolder+FavoriteUserFile);

  case VerifyMultiSelect of
    True:
      begin
        NotAddedGames:= THashedStringList.Create;
        NotAddedGames.BeginUpdate;
        GamesToAdd:= THashedStringList.Create;
        GamesToAdd.BeginUpdate;
        GamesDescription:= THashedStringList.Create;
        GamesDescription.BeginUpdate;

        SelNode:= GamesTreeView.GetFirstSelected;
        repeat
          if SelNode <> nil then
             VerifyGame;
          SelNode:= GamesTreeView.GetNextSelected(SelNode);
        until SelNode = nil;

        NotAddedGames.EndUpdate;
        GamesToAdd.EndUpdate;
        GamesDescription.EndUpdate;
        AddToList:= GamesToAdd.Count > 0;
        if (NotAddedGames.Count > 0) and (not AddToList) then
           GenerateMessage('Games Not Added', 'The following games are already in the list:'+#13#10+NotAddedGames.Text, 2);
      end;
    False:
      begin
        if GetGameData(SelectedNode) then
           begin
             favSystem:= GetSystemFolderName(GameInfoData.eROMIdentification);
             if FavList.IndexOf(GameInfoData.eName+'='+favSystem) <> -1 then
                begin
                  GenerateMessage('Game Not Added', 'This game is already on the list!', 2);
                  AddToList:= False;
                end;
           end;
      end;
  end;

  if AddToList then
     begin
       if Assigned(GamesToAdd) then
          begin
            MultiSelectStr:= '';
            if NotAddedGames.Count > 0 then
               MultiSelectStr:= 'Continue ?'+#13#10+#13#10+
                                'The following games are already in the list:'+#13#10+NotAddedGames.Text+#13#10;
            MultiSelectStr:= MultiSelectStr+'Games To Add:'+#13#10;
            for Loop:=0 to GamesToAdd.Count-1 do
                MultiSelectStr:= MultiSelectStr+Format('%s - [%s, %s]', [GamesDescription[Loop], GamesToAdd.Names[Loop], GamesToAdd.ValueFromIndex[Loop]])+#13#10;
            AddToList:= GenerateMessage('Add Games to Favorites', MultiSelectStr, 1) = mrYes;
          end;
       Application.ProcessMessages;

       FavList.BeginUpdate;
       case Assigned(GamesToAdd) of
         True:
           begin
             for Loop:=0 to GamesToAdd.Count-1 do
                 FavList.Add(GamesToAdd[Loop]);
           end;
         False: FavList.Add(GameInfoData.eName+'='+favSystem);
       end;
       FavList.EndUpdate;
       FavList.SaveToFile(GetFavoritesFolder+FavoriteUserFile);
     end;
  FreeAndNil(FavList);
  FreeAndNil(NotAddedGames);
  FreeAndNil(GamesToAdd);
  FreeAndNil(GamesDescription);
  Result:= AddToList;
  Screen.Cursor:= crDefault;
end;

function TFormMain.DeleteFromFavorite: Boolean;
var
  GameIndex, Loop: Integer;
  favSystem, MultiSelectStr, plSystem: String;
  GamesToDelete, GamesDescription: THashedStringList;
  SelNode: PVirtualNode;

  function VerifyGame: Boolean;
  begin
    if GetGameData(SelNode) then
       begin
         plSystem:= GetSystemFolderName(GameInfoData.eROMIdentification);
         if FavList.IndexOf(GameInfoData.eName+'='+plSystem) <> -1 then
            begin
              GamesToDelete.Add(Format('%s=%s', [GameInfoData.eName, plsystem]));
              GamesDescription.Add(GameInfoData.eDescription);
            end;
       end
    else
       GenerateMessage('Error', 'Atempt to extract name and description information from games list has failed...', 2);
  end;

begin
  Result:= False;
  if not CheckSelected(GamesTreeView) then
     Exit;
  if FavoriteUserFile = '' then
     FavoriteUserFile:= GetFavoriteUserFileName(FavoriteUser);
  if CheckReadOnly(GetFavoritesFolder+FavoriteUserFile) then
     Exit;
  Screen.Cursor:= crHourGlass;
  case FileExists(GetFavoritesFolder+FavoriteUserFile) of
   True:
     begin
       case VerifyMultiSelect of
         True:
           begin
             GamesToDelete:= THashedStringList.Create;
             GamesToDelete.BeginUpdate;
             GamesDescription:= THashedStringList.Create;
             GamesDescription.BeginUpdate;

             SelNode:= GamesTreeView.GetFirstSelected;
             repeat
               if SelNode <> nil then
                  VerifyGame;
               SelNode:= GamesTreeView.GetNextSelected(SelNode);
             until SelNode = nil;

             GamesToDelete.EndUpdate;
             GamesDescription.EndUpdate;
             Result:= GamesToDelete.Count > 0;
             if Result then
                begin
                  MultiSelectStr:= 'Games To Delete:'+#13#10;
                  for Loop:=0 to GamesToDelete.Count-1 do
                      MultiSelectStr:= MultiSelectStr+Format('%s - [%s, %s]', [GamesDescription[Loop], GamesToDelete.Names[Loop], GamesToDelete.ValueFromIndex[Loop]])+#13#10;
                  if GenerateMessage('Delete Games From Favorites', MultiSelectStr, 1) = mrYes then
                     begin
                       FavList.BeginUpdate;
                       for Loop:=0 to GamesToDelete.Count-1 do
                       begin
                         GameIndex:= FavList.IndexOf(GamesToDelete[Loop]);
                         if GameIndex <> -1 then
                            FavList.Delete(GameIndex);
                       end;
                       FavList.EndUpdate;
                       FavList.SaveToFile(GetFavoritesFolder+FavoriteUserFile);
                     end;
                end;
           end;
         False:
            begin
              if GetGameData(SelectedNode) then
                 begin
                   favSystem:= GetSystemFolderName(GameInfoData.eROMIdentification);
                   GameIndex:= FavList.IndexOf(GameInfoData.eName+'='+favSystem);
                   if GameIndex <> -1 then
                      begin
                        Result:= True;
                        FavList.Delete(GameIndex);
                        FavList.SaveToFile(GetFavoritesFolder+FavoriteUserFile);
                      end
                   else
                      GenerateMessage('Operation Failed', 'This game is not in the list!', 2)
                 end;
            end;
       end;
     end;
   False: GenerateMessage('Error', 'File "'+GetFavoritesFolder+FavoriteUserFile+
                          '" not found!', 2);
  end;
  FreeAndNil(GamesToDelete);
  FreeAndNil(GamesDescription);
  if Result then
     begin
       SetGameType(SelectedFilterName, False);
     end;
  Screen.Cursor:= crDefault;
end;

function TFormMain.RemoveQuotes(const DataString: String): String;
begin
  Result:= DataString;
  if DataString = '' then
     Exit;
  if Result[1] = '"' then
     Delete(Result, 1, 1);
  if Result[Length(Result)] = '"' then
     Delete(Result, Length(Result), 1);
end;

procedure TFormMain.LoadFolders_MAME(SystemID: Integer);
var
  MAMEIniFile: THashedStringList;
  Folder, TextLine, IniFile, EntryString: String;
  Loop: Integer;
begin
  if (not FileExists(EmulatorFile[SystemID])) or (EmulatorFile[SystemID] = '') then
     Exit;

  if FormStatus.Visible then
     begin
       FormStatus.LabelMessage.Caption:= 'Loading '+GetSystemIniSection(SystemID)+
                                         ' folders.';
       FormStatus.LabelMessage.Refresh;
     end;
  iniFile:= GetMAMEIniFileName(EmulatorFile[SystemID], SystemID);
  if not FileExists(iniFile) then
     Exit;

  MAMEIniFile:= THashedStringList.Create;
  MAMEIniFile.LoadFromFile(iniFile);
  for Loop:=0 to MAMEIniFile.Count -1 do
  begin
    TextLine:= MAMEIniFile[Loop];
    if TextLine <> '' then
       begin
         EntryString:= XML_GetEntryName(TextLine);
         if EntryString <> '' then
            EntryString:= EntryString+' ';
         if (EntryString = 'rompath ') or
            (EntryString = 'rp ') then
            begin
              Folder:= ExtractMAMEIniValue(TextLine);
              if Folder = '' then
                 Folder:= 'roms';
            end;

         if (EntryString = 'samplepath ') or
            (EntryString = 'sp ') then
            begin
              samplesDir[SystemID]:= ExtractMAMEIniValue(TextLine);
              if SamplesDir[SystemID] = '' then
                 SamplesDir[SystemID]:= 'samples'
              else
                 samplesDir[SystemID]:= samplesDir[SystemID];
            end;

         if EntryString = 'inipath ' then
            begin
              IniFilesDir[SystemID]:= ExtractMAMEIniValue(TextLine);
              if Pos(';', IniFilesDir[SystemID]) <> 0 then
                 IniFilesDir[SystemID]:= 'ini';

              if IniFilesDir[SystemID] = '' then
                 IniFilesDir[SystemID]:= 'ini';
            end;

         if EntryString = 'snapshot_directory ' then
            begin
              if FormMain.imgFolderZipFile[SystemID, 1] = '' then
                 FormMain.imgFolderZipFile[SystemID, 1]:= ExtractMAMEIniValue(TextLine);
            end;

         if SystemID = 1 then
            begin
              if (EntryString = 'ctrlrpath ') or
                 (EntryString = 'ctrlr_directory ') then
                 begin
                   ctrlrDir:= ExtractMAMEIniValue(TextLine);
                   if ctrlrDir = '' then
                      ctrlrDir:= 'ctrlr';
                   AddControllerDefinitionsMenuItems(EmulatorFile[SystemID]);
                 end;
            end;
       end;
  end;
  FreeAndNil(MAMEIniFile);

  ExtractROMsFolders(Folder, SystemID);
  if SystemID in [1, 4, 5, 6] then
     begin
       if samplesDir[SystemID] = '' then
          samplesDir[SystemID]:= ExtractFilePath(EmulatorFile[SystemID])+'samples'
       else
          begin
            if Pos(':', samplesDir[SystemID]) = 0 then
               samplesDir[systemID]:= ExtractFilePath(EmulatorFile[SystemID])+samplesDir[SystemID];
          end;
     end;
end;

procedure TFormMain.LoadFoldersConsole(sysID: Integer);
var
  elCFG: TMemIniFile;
  Folder: String;
begin
  if (not FileExists(FrontendPath+'EmuLoader.ini')) then
     Exit;
  if sysID = 2 then
     begin
       // for ZiNc only
       if (not FileExists(EmulatorFile[sysID])) or (EmulatorFile[sysID] = '') then
          Exit;
     end;

  if FormStatus.Visible then
     begin
       FormStatus.LabelMessage.Caption:= 'Loading '+GetSystemIniSection(sysID)+
                                         ' folders.';
       FormStatus.LabelMessage.Refresh;
     end;
  elCFG:= TMemIniFile.Create(FrontendPath+'EmuLoader.ini');
  Folder:= elCFG.ReadString(GetSystemIniSection(sysID), 'roms_path', '');
  FreeAndNil(elCFG);
  ExtractROMsFolders(Folder, sysID);
end;

procedure TFormMain.LoadFoldersAllSystems;
begin
  LoadFolders_MAME(1);
  LoadFoldersConsole(2); // ZiNc
  LoadFolders_MAME(4);
  LoadFolders_MAME(5);
  LoadFolders_MAME(6);
end;

procedure TFormMain.ExtractROMsFolders(ROMsList: String; SystemID: Integer; ListHolder: TListBox = nil);
var
  PathName: String;

  procedure AddMultipleFolders;
  var
    Loop: Integer;
  begin
    // multiple folders
    for Loop:=1 to Length(ROMsList) do
    begin
      if (ROMsList[Loop] = ';') then
         begin
           case Assigned(ListHolder) of
             True : ListHolder.Items.Add(ExcludeTrailingPathDelimiter(PathName));
             False: emuROMsFolders[SystemID].Add(ExcludeTrailingPathDelimiter(PathName));
           end;
           PathName:= '';
         end
      else
         begin
           if ROMsList[Loop] <> '"' then
              PathName:= PathName+ROMsList[Loop];
           if Loop = Length(ROMsList) then
              begin
                case Assigned(ListHolder) of
                  True : ListHolder.Items.Add(ExcludeTrailingPathDelimiter(PathName));
                  False: emuROMsFolders[SystemID].Add(ExcludeTrailingPathDelimiter(PathName));
                end;
              end;
         end;
    end;
  end;

begin
  case Assigned(emuROMsFolders[SystemID]) of
    True : emuROMsFolders[SystemID].Clear;
    False: emuROMsFolders[SystemID]:= THashedStringList.Create;
  end;

  case Assigned(ListHolder) of
    True:
      begin
        AddMultipleFolders;
      end;
    False:
      begin
        if ROMsList = '' then
           Exit;
        PathName:= '';
        if SystemID in [2, 3] then //single folder
           emuROMsFolders[SystemID].Add(ExcludeTrailingPathDelimiter(ROMsList))
        else
           AddMultipleFolders;
      end;
  end;
end;

function TFormMain.MountFoldersList(ListHolder: TListBox): String;
var
  Loop: Integer;
begin
  Result:= '';
  if Assigned(ListHolder) then
     begin
       for Loop:=0 to ListHolder.Items.Count-1 do
       begin
         if Result <> '' then
            Result:= Result+';'+ListHolder.Items[Loop]
         else
            Result:= ListHolder.Items[Loop];
       end;
     end;
end;

function TFormMain.SearchZIP(const GameName: String; romID: Integer = -1): Boolean;
var
  EmulatorPath, SearchString: String;

  procedure ScanFiles(HolderList: THashedStringList);
  var
    Loop: Integer;
    FolderStr: String;
  begin
    if Assigned(HolderList) and (HolderList.Count > 0) then
       begin
         for Loop:=0 to HolderList.Count -1 do
         begin
           if Pos(':', HolderList.Strings[Loop]) = 0 then
              FolderStr:= EmulatorPath+HolderList.Strings[Loop]+'\'
           else
              FolderStr:= HolderList.Strings[Loop]+'\';

           if SearchForFile(FolderStr, GameName+'.zip', SearchString, False) then
              begin
                Result:= True;
                Break;
              end;
         end;
       end;
  end;

begin
  Result:= False;
  if romID <> -1 then
     GetSystemID(romID);
  EmulatorPath:= IncludeTrailingPathDelimiter(ExtractFilePath(EmulatorFile[SystemID_Number]));
  case SystemID_Number of
    1, 2, 4, 5, 6:
      ScanFiles(emuROMsFolders[SystemID_Number]);
    3: // Daphne
      Result:= FileExists(EmulatorPath+'roms\'+GameName+'.zip');
  end;
end;

function TFormMain.SearchZIPFolder(const GameName: String; romID: Integer = -1): String;
var
  EmulatorPath, SearchString, FileExt: String;

  procedure ScanFiles(HolderList: THashedStringList);
  var
    Loop: Integer;
    FolderStr: String;
  begin
    if Assigned(HolderList) and (HolderList.Count > 0) then
       begin
         for Loop:=0 to HolderList.Count -1 do
         begin
           if Pos(':', HolderList.Strings[Loop]) = 0 then
              FolderStr:= EmulatorPath+HolderList.Strings[Loop]+'\'
           else
              FolderStr:= HolderList.Strings[Loop];

           if SearchForFile(FolderStr, GameName+FileExt, SearchString, False) then
              begin
                Result:= SearchString;
                Break;
              end;
         end;
       end;
  end;

begin
  Result:= '';
  if romID <> -1 then
     GetSystemID(romID);
  FileExt:= '.zip';
  EmulatorPath:= IncludeTrailingPathDelimiter(ExtractFilePath(EmulatorFile[SystemID_Number]));

  case SystemID_Number of
    1, 2, 4, 5, 6:
      ScanFiles(emuROMsFolders[SystemID_Number]);
    3: // Daphne
      begin
        if FileExists(EmulatorPath+'roms\'+GameName+FileExt) then
           Result:= EmulatorPath+'roms\'+GameName+FileExt;
      end;
  end;
end;

function TFormMain.SearchCHDFolder(DiskImageFileName: String; RunningGame: Boolean; romID: Integer = -1): String;
var
  EmulatorPath, SearchString: String;

  procedure ScanFiles(HolderList: THashedStringList);
  var
    Loop: Integer;
    FolderStr: String;
  begin
    if Assigned(HolderList) and (HolderList.Count > 0) then
       begin
         for Loop:=0 to HolderList.Count -1 do
         begin
           if Pos(':', HolderList.Strings[Loop]) = 0 then
              FolderStr:= EmulatorPath+HolderList.Strings[Loop]+'\'
           else
              FolderStr:= HolderList.Strings[Loop]+'\';

           if SearchForFile(FolderStr, DiskImageFileName, SearchString, RunningGame) then
              begin
                Result:= SearchString;
                Break;
              end;
         end;
       end;
  end;

begin
  Result:= '';
  if romID <> -1 then
     GetSystemID(romID);
  if SystemID_Number in [1, 4, 5] then
     begin
       EmulatorPath:= IncludeTrailingPathDelimiter(ExtractFilePath(EmulatorFile[SystemID_Number]));
       ScanFiles(emuROMsFolders[SystemID_Number]);
     end;
end;

function TFormMain.FixCaption(const CaptionString: String): String;
begin
  Result:= CaptionString;
  while Pos('&', Result) > 0 do
    Delete(Result, Pos('&', Result), 1);
end;

function TFormMain.GetControlTypeIndex(const ControlName: String): Integer;
var
  Loop: Integer;
begin
  if ControlName = '' then
     begin
       Result:= 0;
       Exit;
     end
  else
     Result:= -1;

  for Loop:=Low(aControlType) to High(aControlType) do
  begin
    if aControlType[Loop, 1] = ControlName then
       begin
         Result:= Loop;
         Break;
       end;
  end;
  if Result = -1 then
     GenerateMessage('Warning', 'There is a new controller type: '+#13#10+ControlName, 2);
end;

function TFormMain.CreateGamesListXML(sysID: ShortInt): Boolean;
var
  ListXML, ROMsList, games_bios, bios_filenames, ListCPU: THashedStringList;
  FileLine, ROMsDetailsLine, TempString, ROMDataLine, LineResult, EmulatorString, ROMOf: String;
  MainLoop, GameSize, TotalProgress, ScreenIndex: Integer;
  IsResource, IsGameBios, IsGameEntry, GetROM_Details, IsMAME0107, IsVerticalGame: Boolean;
  BiosSet, tempCPU: TMemIniFile;
  tempFile, tmpEmuVersion, romName: String;
  CPUisAdded: Boolean;

  //StartClock: Integer;

const
  ChrMapStr = '&quot;&lt;&gt;&apos;&amp;&nbsp;';

type
  TCharSet = set of char;

  function GetStatusIndex(StatusString: String): Integer;
  begin
    Result:= -1;
    if StatusString = 'good' then
       Result:= 0
    else
    if StatusString = 'imperfect' then
       Result:= 1
    else
    if StatusString = 'preliminary' then
       Result:= 2;
  end;

  function SetIntegerValue(strValue: String; DriverStatus: Boolean): Integer;
  begin
    Result:= -1;
    TempString:= '';
    TempString:= XML_GetEntryValue(FileLine, strValue);
    if TempString <> '' then
       begin
         case DriverStatus of
           True : Result:= GetStatusIndex(TempString);
           False: Result:= StrToInt(TempString);
         end;
       end;
  end;

  function FixDescriptionText(DescriptionString: String): String;
  var
    strPosition: Integer;
  begin
    strPosition:= Pos(', the', LowerCase(DescriptionString));
    if strPosition > 0 then
       begin
         Delete(DescriptionString, strPosition, 5);
         Result:= 'The '+DescriptionString;
       end
    else
       Result:= DescriptionString;
  end;

  function TrimSpaces(const str: String; ChrSpace: TCharSet = [#9, #10, #13, #32]): String;
  var
    i, l: Integer;
  begin
    l:= Length(str);
    i:= 1;
    while (i <= l) and (str[i] in ChrSpace) do Inc(i);
    if i > l then
       Result:= ''
    else
      begin
        while (str[l] in ChrSpace) do Dec(l);
        Result:= Copy(str, i, l-i+1);
      end;
  end;

  function DecodeHTML(const s: String): String;
  var
    j: Integer;
    pp,pe: PChar;
    tmp: String;
  begin
    Result:= TrimSpaces(s);
    if Result = '' then Exit;
    pp:= PChar(Result);
    repeat
      pp:= StrScan(pp, '&');
      if pp = nil then Exit;
      inc(pp);
      j:= pp-PChar(Result);
      pe:= pp;
      while ((pe^ <> #0) and not (pe^ in [' ', ';'])) do Inc(pe);
      if (pp^='#') then
         begin
           if UpCase((pp+1)^) = 'X' then
              (pp+1)^:= '$';
           SetString(tmp, pp+1, pe-pp-1);
           Result[j]:= chr(StrToIntDef(tmp, 32));
           Delete(Result, j+1, pe-pp+1);
         end
      else
         begin
           SetString(tmp,pp-1, pe-pp+1);
           case pos(tmp, ChrMapStr) of
              1: Result[j]:= '"';
              7: Result[j]:= '<';
             11: Result[j]:= '>';
             15: Result[j]:= '''';
             21: Result[j]:= '&';
             26: Result[j]:= ' ';
           else
             Continue;
           end;
           Delete(Result, j+1, pe-pp+1);
         end;
    until False;
  end;

  function Check_Temp_Files(tempFileName: String): Boolean;
  begin
    Result:= FileExists(tempFileName);
    case Result of
      True:
        begin
          Result:= (GetFileSize(tempFileName) > 0);
          if not Result then
             begin
               GenerateMessage('Error', 'File "'+tempFileName+'" is empty! '+
                               'Could not create valid "-listxml" output. Aborting...', 2);
               DeleteFile(tempFileName);
             end
        end;
      False: GenerateMessage('Error', 'File "'+tempFileName+'" was not created! Aborting...', 2);
    end;
  end;

begin
  EmulatorString:= EmulatorFile[sysID];

  if not FileExists(EmulatorString) then
     begin
       GenerateMessage('Operation Failed', Format('File "%s" not found.', [EmulatorString]), 2);
       Result:= False;
       Exit;
     end;

  SetCurrentDir(FrontendPath);
  CheckAndCreateFolder(FrontendPath+GetMachineTypeGamesFolder);

  //StartClock:= GetTickCount;

  tmpEmuVersion:= '';
  tempFile:= 'listxml.xml';

  FormStatus.LabelStatusType.Caption:= 'Create '+GetSystemIniSection(sysID)+' Games List';
  FormStatus.LabelMessage.Caption:= 'Creating "'+tempFile+'" file.';
  if not FormStatus.Visible then
     FormStatus.Show;
  FormStatus.LabelMessage.Refresh;

  LineResult:= SystemStr+EmulatorString+SystemStr+' -listxml > '+SystemStr+FrontendPath+'temp\'+tempFile+SystemStr; // -listxml
  case Win32Platform of
    0,1: RunProcess('command.com /c '+LineResult, True, Get_DOSBox_Status(False), False); //Win9x
      2: RunProcess('cmd.exe /c ' +SystemStr+LineResult+SystemStr, True, Get_DOSBox_Status(False), False); // WinXP and Vista
  end;
  LineResult:= '';

  if FormMain.Visible then
     FormMain.Refresh;

  Result:= Check_Temp_Files(FrontendPath+'temp\'+tempFile);
  if not Result then
     Exit;

  FormStatus.LabelMessage.Caption:= 'Parsing "'+tempFile+'" (1st pass).';
  FormStatus.LabelMessage.Refresh;
  ListXML:= THashedStringList.Create;
  ListXML.LoadFromFile(FrontendPath+'temp\'+tempFile);
  TotalProgress:= ListXML.Count-1;

  if sysID = 1 then
     DeleteFile(FrontendPath+'ini_files\biosset.ini');

  ListCPU:= THashedStringList.Create;
  if FileExists(FrontendPath+'ini_files\cpu.ini') then
     begin
       tempCPU:= TMemIniFile.Create(FrontendPath+'ini_files\cpu.ini');
       if tempCPU.SectionExists(LowerCase(GetSystemIniSection(sysID))) then
          begin
            tempCPU.EraseSection(LowerCase(GetSystemIniSection(sysID)));
            tempCPU.UpdateFile;
          end;
       FreeAndNil(tempCPU);
       ListCPU.LoadFromFile(FrontendPath+'ini_files\cpu.ini');
       if ListCPU.Count > 0 then
          begin
            if ListCPU[ListCPU.Count-1] <> '' then
               ListCPU.Add('');
          end;
     end;

  ListCPU.Add('['+LowerCase(GetSystemIniSection(sysID))+']');

  BiosSet:= TMemIniFile.Create(FrontendPath+'ini_files\biosset.ini');

  FormStatus.SetFocus;
  if ListXML.Count > 0 then
  begin
    DeleteFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(sysID));
    DeleteFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(sysID));
    ListGames:= TMemIniFile.Create(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(sysID));

    ListGames.WriteString('info_file', 'description', '');

    ROMsList:= THashedStringList.Create;
    ROMsList.BeginUpdate;
    IsResource:= False;
    IsGameBios:= False;
    bios_filenames:= THashedStringList.Create;
    bios_filenames.BeginUpdate;

    // now is the tricky part, get all bios sets first
    for MainLoop:=0 to ListXML.Count -1 do
    begin
      FileLine:= TrimLeft(ListXML[MainLoop]);
      if XML_CheckData(FileLine, '<mame build=') then
         begin
           tmpEmuVersion:= DecodeHTML(XML_GetEntryValue(FileLine, '<mame build'));
           case sysID of
             1: tmpEmuVersion:= 'M.A.M.E. v'+tmpEmuVersion;
             4: tmpEmuVersion:= 'A.G.E.M.A.M.E. v'+tmpEmuVersion;
           end;
           TempString:= '';
         end
      else
      if (XML_CheckData(FileLine, '<game ')) and (Pos('runnable="no"', FileLine) <> 0) then
         begin
           ClearMemoryColumnsVariables;
           ROMsDetailsLine:= '';
           TempString:= '';
           GameSize:= 0;
           Delete(FileLine, 1, 6);
           mName:= XML_GetEntryValue(FileLine, 'name');
           if ROMsList.Count > 0 then
              ROMsList.Add(' ');
           ROMsList.Add('['+mName+']');
           IsResource:= True;
           mDriverName:= XML_GetEntryValue(FileLine, 'sourcefile');
         end
      else

      if IsResource then
         begin
           if XML_CheckData(FileLine, '<description>') then
              begin
                mDescription:= DecodeHTML(Copy(FileLine, 14, Pos('</description>', FileLine)-14));
                BiosSet.WriteString('Descriptions', mName, mDescription); // write description
                ROMsList.Add('gmtitle='+mDescription);
              end
           else
           if XML_CheckData(FileLine, '<biosset ') then
              begin
                if not BiosSet.ValueExists('Descriptions', mName) then
                   BiosSet.WriteString('Descriptions', mName, mDescription);
                ROMsDetailsLine:= XML_GetEntryValue(FileLine, 'name'); // name of the biosset
                TempString:= DecodeHTML(XML_GetEntryValue(FileLine, 'description')); // description of the biosset
                if not BiosSet.ValueExists(mName, 'default_bios') then
                   BiosSet.WriteString(mName, 'default_bios', '');
                if not BiosSet.ValueExists(mName, 'selected_bios') then
                   BiosSet.WriteString(mName, 'selected_bios', '');
                if Pos('default="yes"', FileLine) <> 0 then
                   BiosSet.WriteString(mName, 'default_bios', ROMsDetailsLine);
                BiosSet.WriteString(mName, ROMsDetailsLine, TempString);
              end
           else
           if XML_CheckData(FileLine, '<rom ') then
              begin
                romName:= XML_GetEntryValue(FileLine, 'name'); // name of the ROM
                bios_filenames.Add(romName+'='+mName);
                TempString:= XML_GetEntryValue(FileLine, 'size'); // size of the ROM
                if TempString = '' then
                   TempString:= '0';
                ROMsDetailsLine:= TempString+'¬';
                GameSize:= GameSize+StrToInt(TempString);
                TempString:= '';
                TempString:= XML_GetEntryValue(FileLine, 'crc');
                ROMsDetailsLine:= ROMsDetailsLine+TempString+'¬';
                TempString:= '';
                TempString:= XML_GetEntryValue(FileLine, 'status');
                ROMsDetailsLine:= ROMsDetailsLine+TempString+';';
                ROMsList.Add(romName+'='+ROMsDetailsLine);
              end
           else
           if XML_CheckData(FileLine, '</game>') then
              begin
                // verify if is clone or master, neogeo or classic, raster or vector
                case sysID of
                  1: mROMIdentification:= 05; // MAME
                  4: mROMIdentification:= 19; // AGEMAME
                  5: mROMIdentification:= 25; // PinMAME
                end;
                mGameSize:= IntToStr(GameSize);
                ROMDataLine:= PopulateROMDataLine; // new populate with new list format
                ListGames.WriteString('bios', mName, ROMDataLine);
                IsResource:= False;
              end;
         end;
    end;

    ListGames.UpdateFile;

    // get name, cloneof, romof fields
    // if romof, check if a bios is part of the game (master games only!)
    FormStatus.LabelMessage.Caption:= 'Parsing "'+tempFile+'" (2nd pass).';
    FormStatus.LabelMessage.Refresh;
    games_bios:= THashedStringList.Create; // this will hold parent games that have bios
    games_bios.BeginUpdate;
    for MainLoop:=0 to ListXML.Count -1 do
    begin
      FileLine:= TrimLeft(ListXML[MainLoop]);
      if (XML_CheckData(FileLine, '<game ')) and (Pos('runnable="no"', FileLine) = 0) then
         begin
           if Pos('cloneof="', FileLine) = 0 then
              begin
                mName:= '';
                mName:= XML_GetEntryValue(FileLine, 'name');
                if not ListGames.SectionExists(mName) then
                   ListGames.WriteString(mName, mName, '');

                if Pos('romof="', FileLine) <> 0 then
                   begin
                     ROMOf:= '';
                     ROMOf:= XML_GetEntryValue(FileLine, 'romof');
                     IsGameBios:= BiosSet.ValueExists('Descriptions', ROMOf);
                     if IsGameBios then
                        games_bios.Add(mName+'='+ROMOf); // add parent game to the temp list
                   end;
              end;
         end;
      UpdateProgressLabel(MainLoop, TotalProgress);
      Application.ProcessMessages;
    end;
    games_bios.EndUpdate;
    bios_filenames.EndUpdate;
    BiosSet.UpdateFile;

    FormStatus.LabelMessage.Caption:= 'Parsing "'+tempFile+'" (3rd pass).';
    FormStatus.LabelMessage.Refresh;
    // now, the normal games, but no resources this time (bios)
    IsResource:= False;
    IsGameEntry:= False;
    ScreenIndex:= 0;
    CPUisAdded:= False;
    for MainLoop:=0 to ListXML.Count -1 do
    begin
      FileLine:= TrimLeft(ListXML[MainLoop]);
      if (Pos('<game ', FileLine) <> 0) and (Pos('runnable="no"', FileLine) = 0) then
         begin
           ClearMemoryColumnsVariables;
           ROMsDetailsLine:= '';
           TempString:= '';
           GameSize:= 0;
           IsVerticalGame:= False;
           mName:= XML_GetEntryValue(FileLine, 'name');
           mClone:= XML_GetEntryValue(FileLine, 'cloneof');
           ROMOf:= XML_GetEntryValue(FileLine, 'romof');
           mAudioSampleName:= XML_GetEntryValue(FileLine, 'sampleof');
           mDriverName:= XML_GetEntryValue(FileLine, 'sourcefile');
           if ROMsList.Count > 0 then
              ROMsList.Add(' ');
           ROMsList.Add('['+mName+']');
           IsGameBios:= False;
           IsGameEntry:= True;
           IsMAME0107:= False;
           CPUisAdded:= False;
           if mClone <> '' then
              begin
                mBiosName:= games_bios.Values[mClone];
                IsGameBios:= mBiosName <> '';
              end
           else
           if ROMOf <> '' then
              begin
                case Assigned(BiosSet) of
                  True:
                    begin
                      IsGameBios:= BiosSet.ValueExists('Descriptions', ROMOf);
                      if IsGameBios and (mBiosName = '') then
                         mBiosName:= ROMOf;
                    end;
                  False: IsGameBios:= False;
                end;
              end;
         end
      else
      if IsGameEntry then
         begin
           if XML_CheckData(FileLine, '<description>') then
              begin
                mDescription:= DecodeHTML(Copy(FileLine, 14, Pos('</description>', FileLine)-14));
                mDescription:= FixDescriptionText(mDescription);
                ROMsList.Add('gmtitle='+mDescription);
                if mClone <> '' then
                   ROMsList.Add('cloneof='+mClone);
              end
           else
           if XML_CheckData(FileLine, '<year>') then
              mYear:= Copy(FileLine, 7, Pos('</year>', FileLine)-7)
           else
           if XML_CheckData(FileLine, '<manufacturer>') then
              mManufacturer:= DecodeHTML(Copy(FileLine, 15, Pos('</manufacturer>', FileLine)-15))
           else
           if XML_CheckData(FileLine, '<rom ') or XML_CheckData(FileLine, '<disk ') then
              begin
                romName:= XML_GetEntryValue(FileLine, 'name');
                // check for xml tags in rom names for special games
                if mName = 'gt103a2' then
                   romName:= DecodeHTML(romName);

                if mBiosName = '' then
                   GetROM_Details:= True
                else
                   GetROM_Details:= bios_filenames.IndexOfName(romName) = -1;
                if GetROM_Details then
                   begin
                     if Pos('<disk ', FileLine) <> 0 then
                        begin
                          mMediaType:= 1;
                          if LowerCase(ExtractFileExt(romName)) <> '.chd' then
                             romName:= romName+'.chd';
                        end;
                     TempString:= XML_GetEntryValue(FileLine, 'size'); // size of the ROM
                     if TempString = '' then
                        TempString:= '0';
                     ROMsDetailsLine:= TempString+'¬';
                     GameSize:= GameSize+StrToInt(TempString);

                     if Pos('<disk ', FileLine) = 0 then
                        TempString:= XML_GetEntryValue(FileLine, 'crc')
                     else
                        TempString:= XML_GetEntryValue(FileLine, 'md5');

                     ROMsDetailsLine:= ROMsDetailsLine+TempString+'¬';
                     TempString:= '';
                     TempString:= XML_GetEntryValue(FileLine, 'status');
                     ROMsDetailsLine:= ROMsDetailsLine+TempString+';';
                     ROMsList.Add(romName+'='+ROMsDetailsLine);
                   end;
              end
           else
           if XML_CheckData(FileLine, '<sample ') then
              begin
                if mAudioSampleName = '' then
                   mAudioSampleName:= mName;
              end
           else
           if XML_CheckData(FileLine, '<chip ') then
              begin
                if not CPUisAdded then
                   begin
                      if XML_GetEntryValue(FileLine, 'type') = 'cpu' then
                         begin
                           CPUisAdded:= True;
                           ListCPU.Add(mName+'='+XML_GetEntryValue(FileLine, 'name'));
                         end
                   end;
              end
           else
           if XML_CheckData(FileLine, '<video ') then
              begin
                // build 0.106u9 down to 0.84
                TempString:= '';
                TempString:= XML_GetEntryValue(FileLine, 'screen');
                if TempString <> '' then
                   mScreenType1:= Ord(TempString = 'vector');

                TempString:= '';
                TempString:= XML_GetEntryValue(FileLine, 'orientation');
                if TempString <> '' then
                   mScreenRotation1:= Ord(TempString = 'vertical');

                mRefreshRate1:= XML_GetEntryValue(FileLine, 'refresh');
                TempString:= XML_GetEntryValue(FileLine, 'width');
                if TempString <> '' then
                mResolutionWidth1:= StrToInt(TempString);
                TempString:= XML_GetEntryValue(FileLine, 'height');
                if TempString <> '' then
                   mResolutionHeight1:= StrToInt(TempString);
              end
           else
           if XML_CheckData(FileLine, '<display ') then
              begin
                // for 0.106u12 and newer
                TempString:= XML_GetEntryValue(FileLine, 'type');
                if TempString <> '' then
                   TempString:= IntToStr(Ord(TempString = 'vector'))
                else
                   TempString:= '-1';
                case ScreenIndex of
                  0: mScreenType1:= StrToInt(TempString);
                  1: mScreenType2:= StrToInt(TempString);
                  2: mScreenType3:= StrToInt(TempString);
                  3: mScreenType4:= StrToInt(TempString);
                end;

                TempString:= XML_GetEntryValue(FileLine, 'rotate');
                if TempString = '' then
                   TempString:= '-1';
                case ScreenIndex of
                  0: mScreenRotation1:= StrToInt(TempString);
                  1: mScreenRotation2:= StrToInt(TempString);
                  2: mScreenRotation3:= StrToInt(TempString);
                  3: mScreenRotation4:= StrToInt(TempString);
                end;
                TempString:= XML_GetEntryValue(FileLine, 'width');
                if TempString <> '' then
                   begin
                     case ScreenIndex of
                       0: mResolutionWidth1:= StrToInt(TempString);
                       1: mResolutionWidth2:= StrToInt(TempString);
                       2: mResolutionWidth3:= StrToInt(TempString);
                       3: mResolutionWidth4:= StrToInt(TempString);
                     end;
                   end;
                TempString:= XML_GetEntryValue(FileLine, 'height');
                if TempString <> '' then
                   begin
                     case ScreenIndex of
                       0: mResolutionHeight1:= StrToInt(TempString);
                       1: mResolutionHeight2:= StrToInt(TempString);
                       2: mResolutionHeight3:= StrToInt(TempString);
                       3: mResolutionHeight4:= StrToInt(TempString);
                     end;
                   end;

                TempString:= XML_GetEntryValue(FileLine, 'refresh');
                case ScreenIndex of
                  0: mRefreshRate1:= TempString;
                  1: mRefreshRate2:= TempString;
                  2: mRefreshRate3:= TempString;
                  3: mRefreshRate4:= TempString;
                end;
                Inc(ScreenIndex);
                if ScreenIndex > 4 then
                   GenerateMessage('Warning', 'Danger Will Robinson... DANGER! The game '+
                                   mDescription+' - ['+mName+
                                   '] have more than 4 screens!', 2);
              end
           else
           if XML_CheckData(FileLine, '<sound ') then
              mAudioChannels:= SetIntegerValue('channels', False)
           else
           if XML_CheckData(FileLine, '<input ') then
              begin
                mNumberPlayers:= XML_GetEntryValue(FileLine, 'players');
                mControls:= XML_GetEntryValue(FileLine, 'control');
                if mControls = '' then
                   begin
                     mControls:= XML_GetEntryValue(FileLine, 'buttons');
                     if mControls <> '' then
                        mControls:= 'buttons';
                   end;
                mControls:= IntToStr(GetControlTypeIndex(mControls));
              end
           else
           if XML_CheckData(FileLine, '<control ') then
              begin
                // for 0.106u12 and newer
                if not IsMAME0107 then
                   begin
                     mControls:= '';
                     IsMAME0107:= True;
                   end;
                TempString:= XML_GetEntryValue(FileLine, 'type');
                TempString:= IntToStr(GetControlTypeIndex(TempString));
                if mControls <> '' then
                   mControls:= mControls+','+TempString
                else
                   mControls:= TempString;
              end
           else
           if XML_CheckData(FileLine, '<driver ') then
              begin
                mDriverStatus:= SetIntegerValue('status', True);
                mEmulationStatus:= SetIntegerValue('emulation', True);
                mColorStatus:= SetIntegerValue('color', True);
                mSoundStatus:= SetIntegerValue('sound', True);
                mGraphicStatus:= SetIntegerValue('graphic', True);
                mCocktailStatus:= SetIntegerValue('cocktail', True);
                mProtectionStatus:= SetIntegerValue('protection', True);

                TempString:= XML_GetEntryValue(FileLine, 'savestate');
                if TempString <> '' then
                   mSaveState:= Ord(TempString = 'supported');
              end
           else
           if XML_CheckData(FileLine, '</game>') then
              begin
                // must verify if is clone or master, neogeo or classic, raster or vector
                ScreenIndex:= 0;
                if mAudioSampleName <> '' then
                   mAudioSamples:= 0;

                if mClone = '' then
                   begin
                     // it's a master game
                     case sysID of
                       1: mROMIdentification:= 03; // MAME Master
                       4: mROMIdentification:= 17; // AGEMAME Master
                       5: mROMIdentification:= 23; // PinMAME Master
                       6: mROMIdentification:= 28; // HazeMD Master
                     end;
                   end
                else
                   begin
                     // it's a clone game
                     case sysID of
                       1: mROMIdentification:= 04; // MAME Clone
                       4: mROMIdentification:= 18; // AGEMAME Clone
                       5: mROMIdentification:= 24; // PinMAME Clone
                       6: mROMIdentification:= 29; // HazeMD Clone
                     end;
                   end;
                mGameSize:= IntToStr(GameSize);
                ROMDataLine:= PopulateROMDataLine;
                if mClone = '' then
                   ListGames.WriteString(mName, mName, ROMDataLine)
                else
                   ListGames.WriteString(mClone, mName, ROMDataLine);
                IsGameEntry:= False;
              end;
         end;
      UpdateProgressLabel(MainLoop, TotalProgress);
      Application.ProcessMessages;
      if StopBuildDatabase(tempFile) then
         begin
           FreeAndNil(ListXML);
           FreeAndNil(ROMsList);
           FreeAndNil(BiosSet);
           FreeAndNil(ListGames);
           FreeAndNil(ListCPU);
           Result:= False;
           GenerateMessage('Operation Canceled', 'Games list build is canceled!', 2);
           Exit;
         end;
    end;
    ROMsList.EndUpdate;
    FreeAndNil(games_bios);
    FreeAndNil(bios_filenames);
  end;
  FormStatus.LabelMessage.Caption:= 'Saving files and freeing memory.';
  FormStatus.LabelMessage.Refresh;
  FreeAndNil(ListXML);
  FreeAndNil(BiosSet);
  ListCPU.SaveToFile(FrontendPath+'ini_files\cpu.ini');
  FreeAndNil(ListCPU);
  EmulatorChecksum[sysID]:= GetMD5_Value(EmulatorFile[sysID]);
  if tmpEmuVersion = '' then
     begin
       FormStatus.LabelMessage.Caption:= 'Extracting emulator version.';
       FormStatus.LabelMessage.Refresh;
       GetEmulatorVersion(sysID, EmulatorFile[sysID], EmulatorVersion[sysID]);
     end
  else
     EmulatorVersion[sysID]:= tmpEmuVersion;
  ListGames.WriteString('info_file', 'description', GetSystemIniSection(sysID)+' Games List');
  ListGames.WriteString('info_file', 'version', EmulatorVersion[sysID]);
  ListGames.UpdateFile;
  FreeAndNil(ListGames);

  if (Assigned(ROMsList)) and (ROMsList.Count > 0) then
     ROMsList.SaveToFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(sysID))
  else
     GenerateMessage('Error', Format('File "%s" not created. You will not be '+
                     'able to scan and audit games!',
                     [FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(sysID)]), 2);
  FreeAndNil(ROMsList);
  DeleteFile(FrontendPath+'temp\'+tempFile);
  //ShowMessage(IntToStr(GetTickCount-StartClock));
  //FormStatus.LabelProgress.Caption:= '';

  FormMain.Visible:= True;
  Application.ProcessMessages;
end;

function TFormMain.StopBuildDatabase(tempInfo: String): Boolean;
begin
  Result:= False;
  if CancelCurrentOperation then
     begin
       case GenerateMessage('Cancel', 'Stop building the games list ? The current games list will not be changed.', 1) of
         mrYes:
           begin
             Result:= True;
             DeleteFile(FrontendPath+'temp\'+tempInfo);
             FormStatus.KeyPreview:= False;
             FormStatus.Close;
             FormMain.Visible:= True;
             CancelCurrentOperation:= False;
             Application.ProcessMessages;
           end;
         mrNo: CancelCurrentOperation:= False;
       end;
     end;
end;

function TFormMain.CreateGamesListZiNc: Boolean;
var
  GameSetsFile, ROMsList, ZiNcDrivers: THashedStringList;
  FileLine, ROMsDetailsLine, TempString, ROMDataLine, LineResult, EmulatorString: String;
  MainLoop, Loop, TotalProgress, Position1, Position2: Integer;
  tempFile, zName, zClone, zDriverName: String;
  //StartClock, EndClock: Integer;
begin
  EmulatorString:= EmulatorFile[2];
  if not FileExists(EmulatorString) then
     begin
       Result:= False;
       Exit;
     end;
  if not FileExists(FrontendPath+'ini_files\zinc.ini') then
     begin
       Result:= False;
       Exit;
     end;

  FormStatus.LabelStatusType.Caption:= 'Create '+GetSystemIniSection(2)+' Games List';
  FormStatus.LabelMessage.Caption:= 'Creating "'+tempFile+'" file.';
  if not FormStatus.Visible then
     FormStatus.Show;
  FormStatus.LabelMessage.Refresh;
  CheckAndCreateFolder(FrontendPath+GetMachineTypeGamesFolder);
  SetCurrentDir(FrontendPath);

  //StartClock:= GetTickCount;

  tempFile:= 'zinc_gameslist.tmp';
  LineResult:= SystemStr+EmulatorString+SystemStr+' --list-games > '+SystemStr+FrontendPath+'temp\'+tempFile+SystemStr; // --list-sets
  case Win32Platform of
    0,1: RunProcess('command.com /c '+LineResult, True, Get_DOSBox_Status(False), False); //Win9x
      2: RunProcess('cmd.exe /c ' +SystemStr+LineResult+SystemStr, True, Get_DOSBox_Status(False), False); // WinXP and Vista
  end;

  LineResult:= '';
  if FormMain.Visible then
     FormMain.Refresh;

  GameSetsFile:= THashedStringList.Create;
  Result:= FileExists(FrontendPath+'temp\'+tempFile);

  if Result then
  begin
    GameSetsFile.LoadFromFile(FrontendPath+'temp\'+tempFile);
    DeleteFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(2));
    if GameSetsFile.Count > 0 then
       begin
         FormStatus.LabelMessage.Caption:= 'Parsing "'+tempFile+'" (1st pass).';
         FormStatus.LabelMessage.Refresh;
         ListGames:= TMemIniFile.Create(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(2));
         ListGames.WriteString('info_file', 'description', '');
         TotalProgress:= GameSetsFile.Count-1;
         for MainLoop:=1 to GameSetsFile.Count-1 do
         begin
           FileLine:= GameSetsFile[MainLoop];
           if Pos('parent ', FileLine) = 0 then
              begin
                zName:= '';
                Position1:= Pos('[', FileLine);
                Position2:= Pos(',', FileLine);
                if Position2 <> 0 then
                   zName:= Copy(FileLine, Position1+1, (Position2-1)-Position1)
                 else
                    begin
                      Position2:= Pos(']', FileLine);
                      zName:= Copy(FileLine, Position1+1, (Position2-1)-Position1);
                    end;
                 ListGames.WriteString(zName, zName, '');
              end;
           Application.ProcessMessages;
         end;

         FormStatus.LabelMessage.Caption:= 'Parsing "'+tempFile+'" (2st pass).';
         FormStatus.LabelMessage.Refresh;
         if FormPreferences.ZiNcUseMAMEGamesInfo.Checked then
            begin
              ROMsList:= THashedStringList.Create;
              GetGamesList(ROMsList, 1);
              if ROMsList.Count = 0 then
                 FreeAndNil(ROMsList);
            end;
         ZiNcDrivers:= THashedStringList.Create;
         ZiNcDrivers.LoadFromFile(FrontendPath+'ini_files\zinc.ini');
         if GameSetsFile.Count > 0 then
            begin
              for MainLoop:=1 to GameSetsFile.Count-1 do
              begin
                FileLine:= GameSetsFile[MainLoop];
                ClearMemoryColumnsVariables;
                zName:= '';
                zClone:= '';
                ROMsDetailsLine:= '';
                TempString:= '';
                Position1:= Pos('[', FileLine);
                Position2:= Pos(',', FileLine);
                if Position2 <> 0 then
                   begin
                     zName:= Copy(FileLine, Position1+1, (Position2-1)-Position1);
                     TempString:= TrimLeft(Copy(FileLine, Position2+1, Length(FileLine)));
                     Position1:= Pos('parent ', TempString);
                     if Position1 <> 0 then
                        begin
                          Position2:= Pos(',', TempString);
                          if Position2 = 0 then
                             Position2:= Pos(']', TempString);
                          zClone:= Copy(TempString, Position1+7, Position2-(Position1+7));
                        end;
                     Position1:= Pos('BIOS ', TempString);
                     if Position1 <> 0 then
                        begin
                          Position2:= Pos(']', TempString);
                          mBiosName:= Copy(TempString, Position1+5, Position2-(Position1+5));
                        end;
                   end
                else
                   begin
                     Position2:= Pos(']', FileLine);
                     zName:= Copy(FileLine, Position1+1, (Position2-1)-Position1);
                   end;

                zDriverName:=  ZiNcDrivers.Values[zName];
                if Assigned(ROMsList) then
                   begin
                     Loop:= ROMsList.IndexOfName(zName);
                     if Loop <> -1 then
                        GetROMFields(ROMsList, Loop);
                   end;
                mName:= zName;
                mClone:= zClone;
                mDriverName:= zDriverName+'.c';
                if mClone = '' then
                   mROMIdentification:= 08
                else
                   mROMIdentification:= 09;
                mScreenType1:= 0;
                mDriverStatus:= 0;

                mMerged:= Trim(Copy(FileLine, 1, 4));
                Position1:= Pos('[', FileLine);
                mDescription:= Copy(FileLine, 5, Position1-5);

                ROMDataLine:= PopulateROMDataLine;
                if mClone = '' then
                   ListGames.WriteString(mName, mName, ROMDataLine)
                else
                   ListGames.WriteString(mClone, mName, ROMDataLine);
                UpdateProgressLabel(MainLoop, TotalProgress);
                Application.ProcessMessages;
              end;
            end;
         // end of 2nd pass

         FormStatus.LabelMessage.Caption:= 'Saving files and freeing memory.';
         FormStatus.LabelMessage.Refresh;
         FreeAndNil(ROMsList);
         FreeAndNil(ZiNcDrivers);

         ListGames.WriteString('info_file', 'description', GetSystemIniSection(2)+' Games List');
         ListGames.WriteString('info_file', 'version', EmulatorVersion[2]);
         ListGames.UpdateFile;
         FreeAndNil(ListGames);
       end
    else
       Result:= False;
    //EndClock:=GetTickCount;
    //ShowMessage(IntToStr(EndClock-StartClock));
    FreeAndNil(GameSetsFile);
    DeleteFile(FrontendPath+'temp\'+tempFile);
  end;
  FormMain.Visible:= True;
  Application.ProcessMessages;
end;

function TFormMain.CreateGamesListDaphne: Boolean;
var
  GamesSetsFile, MasterCloneList, GameSettings: THashedStringList;
  DaphneLoader: TMemIniFile;
  ROMsDetailsLine, TempString, ROMDataLine, EmulatorString: String;
  MainLoop, Loop, TotalProgress: Integer;
  //StartClock, EndClock: Integer;
begin
  Result:= True;
  CheckAndCreateFolder(FrontendPath+GetMachineTypeGamesFolder);
  EmulatorString:= EmulatorFile[3];
  if not FileExists(EmulatorString) then
     begin
       Result:= False;
       Exit;
     end;
  if not ValidateFile(ExtractFilePath(EmulatorString)+'DaphneLoaderInfo.ini') then
     begin
       GenerateMessage('Error', 'File "DaphneLoaderInfo.ini" not found or is empty. Aborting...', 2);
       Result:= False;
       Exit;
     end;
  if not ValidateFile(FrontendPath+'ini_files\daphne.ini') then
     begin
       GenerateMessage('Error', 'File "'+FrontendPath+'ini_files\daphne.ini" not found or is empty. Aborting...', 2);
       Result:= False;
       Exit;
     end;

  SetCurrentDir(FrontendPath);

  //StartClock:= GetTickCount;

  FormStatus.LabelStatusType.Caption:= 'Create '+GetSystemIniSection(3)+' Games List';
  FormStatus.LabelMessage.Caption:= 'Parsing "ini_files\daphne.ini".';
  if not FormStatus.Visible then
     FormStatus.Show;
  FormStatus.LabelMessage.Refresh;

  MasterCloneList:= THashedStringList.Create;
  DeleteFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(3));
  MasterCloneList.LoadFromFile(FrontendPath+'ini_files\daphne.ini');
  ListGames:= TMemIniFile.Create(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(3));
  ListGames.WriteString('info_file', 'description', '');
  for Loop:=0 to MasterCloneList.Count-1 do
  begin
    mName:= '';
    if MasterCloneList.ValueFromIndex[Loop] = '' then
       mName:= MasterCloneList.Names[Loop];
    if mName <> '' then
       ListGames.WriteString(mName, mName, '');
  end;

  FormStatus.LabelMessage.Caption:= 'Parsing "DaphneLoaderInfo.ini" file.';
  FormStatus.LabelMessage.Refresh;

  DaphneLoader:= TMemIniFile.Create(ExtractFilePath(EmulatorFile[3])+'DaphneLoaderInfo.ini');

  GamesSetsFile:= THashedStringList.Create;
  DaphneLoader.ReadSectionValues('GameList', GamesSetsFile);
  GamesSetsFile.Delete(0);
  GamesSetsFile.BeginUpdate;
  for Loop:=GamesSetsFile.Count-1 downto 0 do
      GamesSetsFile[Loop]:= GamesSetsFile.ValueFromIndex[Loop];
  GamesSetsFile.EndUpdate;
  TotalProgress:= GamesSetsFile.Count-1;

  FormStatus.Show;
  FormStatus.SetFocus;
  if GamesSetsFile.Count > 0 then
     begin
       GameSettings:= THashedStringList.Create;
       for MainLoop:=0 to GamesSetsFile.Count-1 do
       begin
         if DaphneLoader.SectionExists(GamesSetsFile[MainLoop]) then
            begin
              GameSettings.Clear;
              DaphneLoader.ReadSectionValues(GamesSetsFile[MainLoop], GameSettings);
              ClearMemoryColumnsVariables;
              ROMsDetailsLine:= '';
              TempString:= '';
              mMediaType:= 2;
              mDescription:= GamesSetsFile[MainLoop];
              mScreenType1:= 0;
              mDriverStatus:= 0;
              mName:= GameSettings.Values['DriverName'];
              mClone:= MasterCloneList.Values[mName];
              if mClone = '' then
                 mROMIdentification:= 12
              else
                 mROMIdentification:= 13;
            end;
         ROMDataLine:= PopulateROMDataLine;
         if ROMDataLine <> '' then
            begin
              if mClone = '' then
                 ListGames.WriteString(mName, mName, ROMDataLine)
              else
                 ListGames.WriteString(mClone, mName, ROMDataLine);
            end;
         UpdateProgressLabel(MainLoop, TotalProgress);
         Application.ProcessMessages;
       end;
     end;
  FormStatus.LabelMessage.Caption:= 'Saving files and freeing memory.';
  FormStatus.LabelMessage.Refresh;
  ListGames.WriteString('info_file', 'description', GetSystemIniSection(3)+' Games List');
  ListGames.WriteString('info_file', 'version', EmulatorVersion[3]);
  ListGames.UpdateFile;
  FreeAndNil(ListGames);
  FreeAndNil(MasterCloneList);
  FreeAndNil(GamesSetsFile);
  FreeAndNil(GameSettings);
  FreeAndNil(DaphneLoader);

  FullList:= THashedStringList.Create;
  FullList.LoadFromFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(3));
  FullList.BeginUpdate;
  for Loop:=FullList.Count-1 downto 3 do
  begin
    mDriverName:= FullList[Loop];
    if (FullList[Loop] <> '') and
       (mDriverName[1] <> '[') then
       begin
         if FullList.ValueFromIndex[Loop] = '' then
            FullList.Delete(Loop);
       end;
  end;
  FullList.EndUpdate;
  FullList.SaveToFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(3));
  FreeAndNil(FullList);
  Application.ProcessMessages;
  //EndClock:=GetTickCount;
  //ShowMessage(IntToStr(EndClock-StartClock));
end;

procedure TFormMain.GetROMFields(ListHolder: THashedStringList; Index: Integer);
var
  TempField, tmpString: String;
  Loop, FieldNumber: Integer;
begin
  TempField:= '';
  FieldNumber:= 1;
  mName:= ListHolder.Names[Index];
  tmpString:= ListHolder.ValueFromIndex[Index];
  if tmpString = '' then
     Exit;
  for Loop:=1 to Length(tmpString) do
  begin
    if (tmpString[Loop] = '¬') or (tmpString[Loop] = ';') then
       begin
         case FieldNumber of
           01: mROMIdentification:= StrToInt(TempField);
           02: mMediaType:= StrToInt(TempField); // -1 is unknown
           03: mDescription:= TempField;
           04: mYear:= TempField;
           05: mManufacturer:= TempField;

           06: mAudioChannels:= StrToInt(TempField);
           07: mAudioSamples:= StrToInt(TempField);
           08: mAudioSampleName:= TempField;

           09: mControls:= TempField;

           10: mScreenType1:= StrToInt(TempField);
           11: mScreenRotation1:= StrToInt(TempField);
           12: mResolutionWidth1:= StrToInt(TempField);
           13: mResolutionHeight1:= StrToInt(TempField);
           14: mRefreshRate1:= TempField;

           15: mScreenType2:= StrToInt(TempField);
           16: mScreenRotation2:= StrToInt(TempField);
           17: mResolutionWidth2:= StrToInt(TempField);
           18: mResolutionHeight2:= StrToInt(TempField);
           19: mRefreshRate2:= TempField;

           20: mScreenType3:= StrToInt(TempField);
           21: mScreenRotation3:= StrToInt(TempField);
           22: mResolutionWidth3:= StrToInt(TempField);
           23: mResolutionHeight3:= StrToInt(TempField);
           24: mRefreshRate3:= TempField;

           25: mScreenType4:= StrToInt(TempField);
           26: mScreenRotation4:= StrToInt(TempField);
           27: mResolutionWidth4:= StrToInt(TempField);
           28: mResolutionHeight4:= StrToInt(TempField);
           29: mRefreshRate4:= TempField;

           30: mDriverStatus:= StrToInt(TempField);
           31: mEmulationStatus:= StrToInt(TempField);
           32: mColorStatus:= StrToInt(TempField);
           33: mSoundStatus:= StrToInt(TempField);
           34: mGraphicStatus:= StrToInt(TempField);
           35: mCocktailStatus:= StrToInt(TempField);
           36: mProtectionStatus:= StrToInt(TempField);

           37: mBiosName:= TempField;
           38: mClone:= TempField;
           39: mDriverName:= TempField;
           40: mMerged:= TempField;

           41: mGameSize:= TempField;
           42: mSaveState:= StrToInt(TempField);
           43: mNumberPlayers:= TempField;
         end;
         TempField:= '';
         Inc(FieldNumber);
       end
    else
       TempField:= TempField+tmpString[Loop];
  end;
end;

procedure TFormMain.GetGameROMs(ListHolder: THashedStringList; Auditing: Boolean);
var
  TempField, romValues: String;
  Loop, Loop2, FieldNumber: Integer;
begin
  for Loop:=0 to ListHolder.Count-1 do
  begin
    if (ListHolder.Names[Loop] <> 'gmtitle') and
       (ListHolder.Names[Loop] <> 'cloneof') then
       begin
         TempField:= ListHolder.Names[Loop];
         if TempField <> '' then
            begin
              case Auditing of
                False:
                  begin
                    if Assigned(ListROMsName) then
                       ListROMsName.Add(TempField);
                  end;
                True:
                  begin
                    FormAudit.ROMsName.Add(TempField);
                  end;
              end;
            end;
         romValues:= ListHolder.ValueFromIndex[Loop];
         if romValues <> '' then
            begin
              TempField:= '';
              FieldNumber:= 1;
              for Loop2:=1 to Length(romValues) do
              begin
                if (romValues[Loop2] = '¬') or (romValues[Loop2] = ';') then
                   begin
                     case Auditing of
                       False:
                         begin
                           case FieldNumber of
                             1:
                               begin
                                 if Assigned(ListROMsSize) then
                                    ListROMsSize.Add(TempField);
                               end;
                             2:
                               begin
                                 if Assigned(ListROMsCRC) then
                                    begin
                                      ListROMsCRC.Add(TempField);
                                      Break;
                                    end;
                               end;
                           end;
                         end;
                       True:
                         begin
                           case FieldNumber of
                             1: FormAudit.ROMsSize.Add(TempField);
                             2: FormAudit.ROMsCRC.Add(TempField);
                             3: FormAudit.ROMsStatus.Add(TempField);
                           end;
                         end;
                     end;
                     TempField:= '';
                     Inc(FieldNumber);
                   end
                else
                   TempField:= TempField+romValues[Loop2];
              end;
            end;
       end;
  end;
end;

function TFormMain.LoadGames(SystemID: Integer; IsFavorite: Boolean; FavFile: String = ''): Boolean;
begin
  case IsFavorite of
    True:
      begin
        Result:= FavFile <> '';
        case Result of
          True:
            begin
              Result:= ValidateFile(GetFavoritesFolder+FavFile);
              if Result then
                 begin
                   if not Assigned(FavList) then
                      FavList:= THashedStringList.Create;
                   FavList.LoadFromFile(GetFavoritesFolder+FavFile);
                 end;
            end;
          False: GenerateMessage('Error', 'Trying to load favorites but the favorite filename is not defined!', 2)
        end;
      end;
    False:
      begin
        Result:= GetGamesList(CompleteGamesList, SystemID);
      end;
  end;
end;

function TFormMain.ScanMainFilter(ROM_ID: Integer): Boolean;
begin
  // Check Arcade systems filters
  if not PopupArcadeListAll.Checked then
     begin
       if ((ROM_ID in [00..05]) and (not PopupArcadeMAME.Checked)) or
          ((ROM_ID in [06..09]) and (not PopupArcadeZiNc.Checked)) or
          ((ROM_ID in [10..13]) and (not PopupArcadeDaphne.Checked)) or
          ((ROM_ID in [14..19]) and (not PopupArcadeAGEMAME.Checked)) or
          ((ROM_ID in [20..25]) and (not PopupArcadePinMAME.Checked)) or
          ((ROM_ID in [26..29]) and (not PopupArcadeHazeMD.Checked)) then
          begin
            Result:= False;
            Exit;
          end;
     end;

  case ROM_ID of
    00: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // MAME Master (have)
    01: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // MAME Clone (have)
    02: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                 (not PopupShowMiss.Checked); // MAME Bios (have)
    03: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // MAME Master (miss)
    04: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // MAME Clone (miss)
    05: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                  (not PopupShowHave.Checked); // MAME Bios (miss)

    06: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // ZiNc Master (have)
    07: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // ZiNc Clone (have)
    08: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // ZiNc Master (miss)
    09: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // ZiNc Clone (miss)

    10: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // Daphne Master (have)
    11: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // Daphne Clone (have)
    12: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // Daphne Master (miss)
    13: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // Daphne Clone (miss)

    14: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // AGEMAME Master (have)
    15: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // AGEMAME Clone (have)
    16: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                 (not PopupShowMiss.Checked); // AGEMAME Bios (have)
    17: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // AGEMAME Master (miss)
    18: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // AGEMAME Clone (miss)
    19: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                 (not PopupShowHave.Checked); // AGEMAME Bios (miss)

    20: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // PinMAME Master (have)
    21: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // PinMAME Clone (have)
    22: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                 (not PopupShowMiss.Checked); // PinMAME Bios (have)
    23: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // PinMAME Master (miss)
    24: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // PinMAME Clone (miss)
    25: Result:= (not ButtonGameFilterHideBios.Down) and (not PopupShowClone.Checked) and
                 (not PopupShowHave.Checked); // PinMAME Bios (miss)

    26: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // HazeMD Master (have)
    27: Result:= (not PopupShowMaster.Checked) and (not PopupShowMiss.Checked); // HazeMD Clone (have)
    28: Result:= (not PopupShowClone.Checked) and (not PopupShowHave.Checked); // HazeMD Master (miss)
    29: Result:= (not PopupShowMaster.Checked) and (not PopupShowHave.Checked); // HazeMD Clone (miss)

    //32: Result:= (not PopupShowClone.Checked) and (not PopupShowMiss.Checked); // Custom Game
    else
       Result:= True;
  end;
end;

function TFormMain.CheckParentalLock(romID: Integer; GameName: String): Boolean;
begin
  if MenuParentalLock.Checked then
     Result:= (ParentalLockGamesList.IndexOf(GameName+'='+GetSystemFolderName(romID)) <> -1);
end;

function TFormMain.FilterGamesList(FilterName: String): Boolean;
var
  DeleteGame: Boolean;
  biosListFile: THashedStringList;

  function CheckDriverFilter: Boolean;
  begin
    DeleteGame:= mDriverName <> (FilterName+'.c');
  end;

  function CheckBiosFilter(FilterName: String): Boolean;
  begin
    DeleteGame:= mBiosName <> FilterName;
  end;

begin
  biosListFile:= nil;
  DeleteGame:= False;

  case ButtonGameFilterWorkingNonWorking.Tag of
      1: DeleteGame:= (mDriverStatus = 2);
      2: DeleteGame:= (mDriverStatus <> 2);
  end;
  if (ButtonGameFilterHideBios.Down) and (not DeleteGame) then
     DeleteGame:= mROMIdentification in [02, 05, 16, 19, 22, 25];

  if (not DeleteGame) then
     begin
       if FilterName = 'classic' then // Classic games (excludes Neo Geo)
          DeleteGame:= mDriverName = 'neogeo.c'
       else
       if FilterName = 'neogeo' then
          CheckDriverFilter // Neo Geo
       else
       if FilterName = 'vector' then
          begin
            DeleteGame:= (mScreenType1 = 0) or (mScreenType2 = 0) or
                         (mScreenType3 = 0) or (mScreenType4 = 0) or
                         (mROMIdentification in [02, 05]); // Vector
          end
       else
       if FilterName = 'chd' then
          DeleteGame:= mMediaType <> 1 // Compressed Hunks of Data (CHD)
       else
       if FilterName = 'pgm' then
          CheckDriverFilter // Polygame Master System (PGM)
       else
       if FilterName = 'arcadia' then
          CheckDriverFilter // Arcadia System
       else
       if FilterName = 'decocass' then
          CheckDriverFilter // DECO Cassette System
       else
       if FilterName = 'simpl156' then
          CheckDriverFilter // Data East Simple 156
       else
       if FilterName = 'vegas' then
          CheckDriverFilter // Atari / Midway Vegas
       else
       if FilterName = 'irem' then
          begin
            //Irem Old School
            DeleteGame:= (mDriverName <> 'mpatrol.c') and // Moon Patrol
                         (mDriverName <> 'm62.c') and // Irem "M62" system
                         (mDriverName <> 'm72.c') and // Irem "M72" system
                         (mDriverName <> 'm90.c') and // Irem M90/M97 system
                         (mDriverName <> 'm92.c') and // Irem "M92" system
                         (mDriverName <> 'm107.c') and // Irem "M107" system
                         (mDriverName <> 'vigilant.c'); // Vigilante hardware
          end
       else
       if FilterName = 'ssv' then
          CheckDriverFilter // Seta, Sammy, Visco System (SSV)
       else
       if FilterName = 'midway' then
          begin
            // Midway (T, V, Wolf, X, Y, Z, Zeus) System
            DeleteGame:= (mDriverName <> 'midtunit.c') and // Midway T-unit system
                         (mDriverName <> 'midvunit.c') and // Midway V-unit system
                         (mDriverName <> 'midwunit.c') and // Midway Wolf-unit system
                         (mDriverName <> 'midxunit.c') and // Midway X-unit system
                         (mDriverName <> 'midyunit.c') and // Williams/Midway Y/Z-unit system
                         (mDriverName <> 'midzeus.c'); // Midway Zeus system
          end
       else
       if FilterName = 'seattle' then
          CheckDriverFilter // Atari/Midway Phoenix/Seattle/Flagstaff hardware
       else
       if FilterName = 'capcom' then
          begin
            // all capcom sub-filters
            DeleteGame:= (mDriverName <> 'cps1.c') and
                         (mDriverName <> 'cps2.c') and
                         (mDriverName <> 'cps3.c') and
                         (CheckBiosFilter('cpzn1')) and
                         (CheckBiosFilter('cpzn2')) and
                         (mDriverName <> 'gng.c') and
                         (mDriverName <> 'gunsmoke.c') and
                         (mDriverName <> 'higemaru.c') and
                         (mDriverName <> 'sonson.c') and
                         (mDriverName <> 'commando.c') and
                         (mDriverName <> 'tigeroad.c');
          end
       else
       if FilterName = 'cps1' then
          CheckDriverFilter // Capcom System 1 (CPS-1)
       else
       if FilterName = 'cps2' then
          CheckDriverFilter // Capcom System 2 (CPS-2)
       else
       if FilterName = 'cps3' then
          CheckDriverFilter // Capcom System 3 (CPS-3)
       else
       if FilterName = 'cpzn1' then
          CheckBiosFilter('cpzn1') // Capcom ZN-1
       else
       if FilterName = 'cpzn2' then
          CheckBiosFilter('cpzn2') // Capcom ZN-2
       else
       if FilterName = 'capcom_oldschool' then
          begin
            // Capcom (Old School)
            DeleteGame:= (mDriverName <> 'gng.c') and // Ghosts'n Goblins hardware
                         (mDriverName <> 'gunsmoke.c') and // Gun Smoke hardware
                         (mDriverName <> 'higemaru.c') and // Higemary hardware
                         (mDriverName <> 'sonson.c') and // Sonson hardware
                         (mDriverName <> 'commando.c') and // Commando hardware
                         (mDriverName <> 'tigeroad.c'); // Capcom ZN-2
          end
       else
       if FilterName = 'sega' then
          begin
            // all Sega sub-filters
            DeleteGame:= (mDriverName <> 'system1.c') and
                         (mDriverName <> 'system16.c') and
                         (mDriverName <> 'segahang.c') and
                         (mDriverName <> 'segaorun.c') and
                         (mDriverName <> 'segas16a.c') and
                         (mDriverName <> 'segas16b.c') and
                         (mDriverName <> 'system18.c') and
                         (mDriverName <> 'segas18.c') and
                         (mDriverName <> 'system24.c') and
                         (mDriverName <> 'system32.c') and
                         (mDriverName <> 'segas32.c') and
                         (mDriverName <> 'stv.c') and
                         (mDriverName <> 'segaxbd.c') and
                         (mDriverName <> 'segaybd.c') and
                         (mDriverName <> 'segac2.c') and
                         (mDriverName <> 'megatech.c') and
                         (mDriverName <> 'megaplay.c') and
                         (mDriverName <> 'model1.c') and
                         (mDriverName <> 'model2.c') and
                         (mDriverName <> 'model3.c');
          end
       else
       if FilterName = 'system1' then
          CheckDriverFilter // Sega System 1 / System 2
       else
       if FilterName = 'system16' then
          begin
            // Sega System 16
            DeleteGame:= (mDriverName <> 'system16.c') and // Sega System 16 hardware
                         (mDriverName <> 'segahang.c') and // Sega Hang-On hardware
                         (mDriverName <> 'segaorun.c') and // Sega Out Run hardware
                         (mDriverName <> 'segas16a.c') and // Sega pre-System 16 & System 16A hardware
                         (mDriverName <> 'segas16b.c'); // Sega System 16B hardware
          end
       else
       if FilterName = 'system18' then
          begin
            // Sega System 18
            DeleteGame:= (mDriverName <> 'system18.c') and
                         (mDriverName <> 'segas18.c');
          end
       else
       if FilterName = 'system24' then
          CheckDriverFilter // Sega System 24
       else
       if FilterName = 'system32' then
          begin
            // Sega System 32 / Multi 32 hardware
            DeleteGame:= (mDriverName <> 'system32.c') and
                         (mDriverName <> 'segas32.c');
          end
       else
       if FilterName = 'stv' then
          CheckDriverFilter // Sega Titan Vidoe (ST-V)
       else
       if FilterName = 'segaxybd' then
          begin
            DeleteGame:= (mDriverName <> 'segaxbd.c') and // Sega X-board hardware
                         (mDriverName <> 'segaybd.c'); // Sega Y-board hardware
          end
       else
       if FilterName = 'segac2' then
          CheckDriverFilter // Sega System C/C2 Driver
       else
       if FilterName = 'megatech_megaplay' then
          begin
            DeleteGame:= (mDriverName <> 'megatech.c') and // Sega MegaTech
                         (mDriverName <> 'megaplay.c'); // Sega MegaPlay
          end
       else
       if FilterName = 'model1' then
          CheckDriverFilter // Sega Model 1
       else
       if FilterName = 'model2' then
          CheckDriverFilter // Sega Model 2
       else
       if FilterName = 'model3' then
          CheckDriverFilter // Sega Model 3
       else
       if FilterName = 'konami' then
          begin
            // all konami sub-filters
            DeleteGame:= (mDriverName <> 'konamigx.c') and
                         (mDriverName <> 'konamigv.c') and
                         (mDriverName <> 'konamigq.c') and
                         (mDriverName <> 'tmnt.c') and
                         (mDriverName <> 'simpsons.c') and
                         (mDriverName <> 'moo.c') and
                         (mDriverName <> 'parodius.c') and
                         (mDriverName <> 'xexex.c') and
                         (mDriverName <> 'trackfld.c') and
                         (mDriverName <> 'gyruss.c') and
                         (mDriverName <> 'hyperspt.c') and
                         (mDriverName <> 'yiear.c') and
                         (mDriverName <> 'pingpong.c') and
                         (mDriverName <> 'gberet.c') and
                         (mDriverName <> 'hcastle.c') and
                         (mDriverName <> 'contra.c') and
                         (mDriverName <> 'thunderx.c') and
                         (mDriverName <> '88games.c') and
                         (mDriverName <> 'nemesis.c') and
                         (mDriverName <> 'twin16.c') and
                         (mDriverName <> 'gradius3.c') and
                         (mDriverName <> 'pooyan.c');
          end
       else
       if FilterName = 'konamigx' then
          CheckDriverFilter // Konami System GX
       else
       if FilterName = 'konamigv' then
          CheckDriverFilter // Konami System GV
       else
       if FilterName = 'konamigq' then
          CheckDriverFilter // Konami GQ System
       else
       if FilterName = 'ksys573' then
          CheckDriverFilter // Konami System 573
       else
       if FilterName = 'konami_oldschool1' then
          begin
            // Konami - Old School 1
            DeleteGame:= (mDriverName <> 'tmnt.c') and // Konami 68000 based games
                         (mDriverName <> 'simpsons.c') and // The Simpsons hardware
                         (mDriverName <> 'moo.c') and // Wild West C.O.W. hardware
                         (mDriverName <> 'parodius.c') and // Konami GX955 hardware
                         (mDriverName <> 'xexex.c'); // Xexex hardware
          end
       else
       if FilterName = 'konami_oldschool2' then
          begin
            // Konami - Old School 2
            DeleteGame:= (mDriverName <> 'trackfld.c') and // Track'n'Field hardware
                         (mDriverName <> 'gyruss.c') and // Gyruss hardware
                         (mDriverName <> 'hyperspt.c') and // Hyper Sports hardware
                         (mDriverName <> 'yiear.c') and // Yie Ar Kung-Fu hardware
                         (mDriverName <> 'pingpong.c') and // Ping Pong hardware
                         (mDriverName <> 'gberet.c') and // Green Beret hardware
                         (mDriverName <> 'hcastle.c') and // Haunted Castle hardware
                         (mDriverName <> 'contra.c') and // Contra hardware
                         (mDriverName <> 'thunderx.c') and // Super Contra hardware
                         (mDriverName <> '88games.c') and // 88 Games hardware
                         (mDriverName <> 'nemesis.c') and // Nemesis hardware
                         (mDriverName <> 'twin16.c') and // Konami Twin16 hardware
                         (mDriverName <> 'gradius3.c') and // Konami GX945 hardware
                         (mDriverName <> 'pooyan.c'); // Konami Pooyan hardware
          end
       else
       if FilterName = 'taito' then
          begin
            // all taito sub-filters
            DeleteGame:= (mDriverName <> 'taito_f2.c') and
                         (mDriverName <> 'taito_f3.c') and
                         (CheckBiosFilter('taitofx1')) and
                         (mDriverName <> 'taito_b.c') and
                         (mDriverName <> 'taito_l.c') and
                         (mDriverName <> 'taito_h.c') and
                         (mDriverName <> 'taito_x.c') and
                         (mDriverName <> 'taito_z.c') and
                         (mDriverName <> 'taitojc.c') and
                         (mDriverName <> 'taitosj.c') and
                         (mDriverName <> 'halleys.c') and
                         (mDriverName <> 'tsamurai.c') and
                         (mDriverName <> 'fastfred.c') and
                         (mDriverName <> 'superqix.c') and
                         (mDriverName <> 'flstory.c') and
                         (mDriverName <> 'slapfght.c') and
                         (mDriverName <> 'tnzs.c') and
                         (mDriverName <> 'arkanoid.c') and
                         (mDriverName <> 'bublbobl.c') and
                         (mDriverName <> 'rainbow.c') and
                         (mDriverName <> 'lkage.c');
          end
       else
       if FilterName = 'taito_f2' then
          CheckDriverFilter // Taito F2 System
       else
       if FilterName = 'taito_f3' then
          CheckDriverFilter // Taito F3 System
       else
       if FilterName = 'taito_fx1' then
          CheckBiosFilter('taitofx1') // Taito FX1
       else
       if FilterName = 'taito_misc' then
          begin
            // Taito B / L / H / X / Z / JC / SJ Systems
            DeleteGame:= (mDriverName <> 'taito_b.c') and // Taito B System
                         (mDriverName <> 'taito_l.c') and // Taito L System
                         (mDriverName <> 'taito_h.c') and // Taito H System
                         (mDriverName <> 'taito_x.c') and // Taito X System
                         (mDriverName <> 'taito_z.c') and // Taito Z System
                         (mDriverName <> 'taitojc.c') and // Taito JC System
                         (mDriverName <> 'taitosj.c'); // Taito SJ System
          end
       else
       if FilterName = 'taito_oldschool' then
          begin
            // Taito - Old School
            DeleteGame:= (mDriverName <> 'halleys.c') and // Halley's Comet hardware
                         (mDriverName <> 'tsamurai.c') and // Samurai hardware
                         (mDriverName <> 'fastfred.c') and // Fast Freddie/Jump Coaster hardware
                         (mDriverName <> 'superqix.c') and // Super Qix hardware
                         (mDriverName <> 'flstory.c') and // The FairyLand Story hardware
                         (mDriverName <> 'slapfght.c') and // Slap Fight hardware
                         (mDriverName <> 'tnzs.c') and // The NewZealand Story hardware
                         (mDriverName <> 'arkanoid.c') and // Arkanoid hardware
                         (mDriverName <> 'bublbobl.c') and // Bubble Bobble hardware
                         (mDriverName <> 'rainbow.c') and // Rainbow Islands hardware
                         (mDriverName <> 'lkage.c'); // Legend of Kage hardware
          end
       else
       if FilterName = 'namco' then
          begin
            // all namco sub-filters
            DeleteGame:= (mDriverName <> 'namcos1.c') and
                         (mDriverName <> 'namcos2.c') and
                         (mDriverName <> 'namcos10.c') and
                         (mDriverName <> 'namcos11.c') and
                         (mDriverName <> 'namcos12.c') and
                         (mDriverName <> 'namcos21.c') and
                         (mDriverName <> 'namcos22.c') and
                         (mDriverName <> 'namcos23.c') and
                         (mDriverName <> 'namcona1.c') and
                         (mDriverName <> 'namconb1.c') and
                         (mDriverName <> 'namcond1.c') and
                         (mDriverName <> 'namcofl.c') and
                         (mDriverName <> 'galaga.c') and
                         (mDriverName <> 'mappy.c') and
                         (mDriverName <> 'gaplus.c') and
                         (mDriverName <> 'baraduke.c') and
                         (mDriverName <> 'rallyx.c') and
                         (mDriverName <> 'pacland.c') and
                         (mDriverName <> 'pacman.c') and
                         (mDriverName <> 'polepos.c');
          end
       else
       if FilterName = 'namcos1' then
          CheckDriverFilter // Namco System 1
       else
       if FilterName = 'namcos2' then
          CheckDriverFilter // Namco System 2
       else
       if FilterName = 'namcos11' then
          begin
            DeleteGame:= (mDriverName <> 'namcos10.c') and // Namco System 10 - Arcade PSX hardware
                         (mDriverName <> 'namcos11.c'); // Namco System 11 - Arcade PSX hardware
          end
       else
       if FilterName = 'namcos12' then
          CheckDriverFilter // Namco System 12 - Arcade PSX hardware
       else
       if FilterName = 'namcos21' then
          CheckDriverFilter // Namco System 21
       else
       if FilterName = 'namcos22' then
          begin
            DeleteGame:= (mDriverName <> 'namcos22.c') and // Namco (Super) System 22
                         (mDriverName <> 'namcos23.c'); // Namco (Super) System 23
          end
       else
       if FilterName = 'namco_misc' then
          begin
            // Namco System NA-1 / NA-2 / NB-1 / ND-1 / FL
            DeleteGame:= (mDriverName <> 'namcona1.c') and // Namco System NA-1 / NA-2
                         (mDriverName <> 'namconb1.c') and // Namco System NB-1
                         (mDriverName <> 'namcond1.c') and // Namco System ND-1
                         (mDriverName <> 'namcofl.c'); // Namco System FL
          end
       else
       if FilterName = 'namco_oldschool' then
          begin
            // Namco - Old School
            DeleteGame:= (mDriverName <> 'galaga.c') and // Galaga hardware
                         (mDriverName <> 'mappy.c') and // Mappy hardware
                         (mDriverName <> 'gaplus.c') and // GaPlus hardware
                         (mDriverName <> 'baraduke.c') and // Baraduke hardware
                         (mDriverName <> 'rallyx.c') and // Rally-X hardware
                         (mDriverName <> 'pacland.c') and // Pac-Land hardware
                         (mDriverName <> 'pacman.c') and // Pac-Man hardware
                         (mDriverName <> 'polepos.c'); // Pole Position hardware
          end
       else
       if FilterName = 'atari' then
          begin
            // all atari sub-filters
            DeleteGame:= (mDriverName <> 'atarisy1.c') and
                         (mDriverName <> 'atarisy2.c') and
                         (mDriverName <> 'atarig1.c') and
                         (mDriverName <> 'atarig42.c') and
                         (mDriverName <> 'atarigt.c') and
                         (mDriverName <> 'atarigx2.c') and
                         (mDriverName <> 'centiped.c') and
                         (mDriverName <> 'ccastles.c') and
                         (mDriverName <> 'irobot.c') and
                         (mDriverName <> 'missile.c') and
                         (mDriverName <> 'arcadecl.c') and
                         (mDriverName <> 'badlands.c') and
                         (mDriverName <> 'blstroid.c') and
                         (mDriverName <> 'gauntlet.c') and
                         (mDriverName <> 'harddriv.c') and
                         (mDriverName <> 'klax.c') and
                         (mDriverName <> 'atetris.c') and
                         (mDriverName <> 'toobin.c') and
                         (mDriverName <> 'xybots.c');
          end
       else
       if FilterName = 'atarisy1' then
          CheckDriverFilter // Atari System 1 hardware
       else
       if FilterName = 'atarisy2' then
          CheckDriverFilter // Atari System 2 hardware
       else
       if FilterName = 'atari_misc' then
          begin
            // Atari G1 / G42 / GT / GX2
            DeleteGame:= (mDriverName <> 'atarig1.c') and // Atari G1 hardware
                         (mDriverName <> 'atarig42.c') and // Atari G42 hardware
                         (mDriverName <> 'atarigt.c') and // Atari GT hardware
                         (mDriverName <> 'atarigx2.c'); // Atari GX2 hardware
          end
       else
       if FilterName = 'atari_oldschool' then
          begin
            // Atari - Old School
            DeleteGame:= (mDriverName <> 'centiped.c') and // Atari Centiped hardware
                         (mDriverName <> 'ccastles.c') and // Atari Crystal Castles hardware
                         (mDriverName <> 'irobot.c') and // Atari I, Robot hardware
                         (mDriverName <> 'missile.c') and // Atari Missile Command hardware
                         (mDriverName <> 'arcadecl.c') and // Atari Arcade Classics hardware
                         (mDriverName <> 'badlands.c') and // Atari Bad Lands hardware
                         (mDriverName <> 'blstroid.c') and // Atari Blasteroids hardware
                         (mDriverName <> 'gauntlet.c') and // Atari Gauntlet hardware
                         (mDriverName <> 'harddriv.c') and // Atari polygon racer games
                         (mDriverName <> 'klax.c') and // Atari Klax hardware
                         (mDriverName <> 'atetris.c') and // Atari Tetris hardware
                         (mDriverName <> 'toobin.c') and // Atari Toobin' hardware
                         (mDriverName <> 'xybots.c'); // Atari Xybots hardware
          end
       else
       if FilterName = 'nintendo' then
          begin
            // all nintendo sub-filters
            DeleteGame:= (mDriverName <> 'playch10.c') and
                         (mDriverName <> 'nss.c') and
                         (mDriverName <> 'vsnes.c') and
                         (mDriverName <> 'dkong.c') and
                         (mDriverName <> 'popeye.c') and
                         (mDriverName <> 'punchout.c') and
                         (mDriverName <> 'mario.c');
          end
       else
       if FilterName = 'playch10' then
          CheckDriverFilter // PlayChoice-10
       else
       if FilterName = 'nss' then
          CheckDriverFilter // Nintendo Super System
       else
       if (FilterName = 'vsnes') or (FilterName = 'nvs') then
          CheckDriverFilter // Nintendo VS UniSystem and DualSystem
       else
       if FilterName = 'nintendo_oldschool' then
          begin
            // Nintendo - Old School
            DeleteGame:= (mDriverName <> 'dkong.c') and // Donkey Kong hardware
                         (mDriverName <> 'popeye.c') and // Popeye hardware
                         (mDriverName <> 'punchout.c') and // Punchout hardware
                         (mDriverName <> 'mario.c'); // Mario Bros. hardware
          end;
     end;
  FreeAndNil(biosListFile);
  Result:= DeleteGame;
end;

function TFormMain.AddGames(const FilterName: String; SelectItem: Boolean): Boolean;
var
  Loop, mParent: Integer;
  tempList,
  iniNumPlayers: THashedStringList;
  Node, ParentNode: PVirtualNode;
  SystemNode: packed array[1..MaxArcadeSystems] of PVirtualNode;
  GameCPU: TMemIniFile;
  NumScr: ShortInt;

  function CreateSystemNodes(var nodeID: PVirtualNode; sysID: Integer): Boolean;
  begin
    NodeID:= GamesTreeView.AddChild(nil);
    GameInfoData:= GamesTreeView.GetNodeData(nodeID);

    GameInfoData.eParent:= -1;
    GameInfoData.eROMIdentification:= sysID; // romID will hold the system ID
    GameInfoData.eImageIndex:= sysID+MaxGameID;
    case FormPreferences.ShowEmuVersionSystemDescription.Checked of
      True:
        begin
          if EmulatorVersion[sysID] <> '' then
             GameInfoData.eDescription:= EmulatorVersion[sysID]
          else
             GameInfoData.eDescription:= GetEmuFullDescription(sysID);
        end;
      False:
        begin
          GameInfoData.eDescription:= GetEmuFullDescription(sysID);
        end;
    end;
    GameInfoData.eAudioSamples:= -1;
    GameInfoData.eNumberScreens:= -1;
    GameInfoData.eScreenType1:= -1;
    GameInfoData.eScreenRotation1:= -1;
    GameInfoData.eResolutionWidth1:= -1;
    GameInfoData.eResolutionHeight1:= -1;
    GameInfoData.eScreenType2:= -1;
    GameInfoData.eScreenRotation2:= -1;
    GameInfoData.eScreenType3:= -1;
    GameInfoData.eScreenRotation3:= -1;
    GameInfoData.eScreenType4:= -1;
    GameInfoData.eScreenRotation4:= -1;
    GameInfoData.eDriverStatus:= -1;
    GameInfoData.eEmulationStatus:= -1;
    GameInfoData.eColorStatus:= -1;
    GameInfoData.eSoundStatus:= -1;
    GameInfoData.eGraphicStatus:= -1;
    GameInfoData.eCocktailStatus:= -1;
    GameInfoData.eProtectionStatus:= -1;
    GameInfoData.eName:= LowerCase(GetSystemIniSection(sysID));
    GameInfoData.eDriverName:= 'system_node';
    GameInfoData.eControlType:= 0;
    GameInfoData.eSaveState:= -1;
  end;

  function AddChildNode(const NodeName: PVirtualNode): Boolean;
  begin
    if NodeName <> nil then
       Node:= GamesTreeView.AddChild(NodeName)
    else
       Node:= GamesTreeView.AddChild(nil);
  end;

  function AddGameTreeView: Boolean;
  begin
    case ButtonViewMode.Tag of
      0: Node:= GamesTreeView.AddChild(nil); // standard
      1: // grouped
         begin
           case GameIsClone(mClone) of
             True:
               begin
                 if mParent <> -1 then
                    Node:= GamesTreeView.AddChild(ParentNode)
                 else
                    GenerateMessage('Error', 'This is a clone and the parent is not added yet!!!'+#13#10+
                                    'name: '+mName+#13#10+'clone of: '+mClone, 2);
               end;
             False:
               begin
                 // add root node (parent only)
                 Node:= GamesTreeView.AddChild(nil);
                 ParentNode:= Node;
                 mParent:= Node.Index;
               end;
           end;
         end;
      2: // system
        begin
          // add root node (parent only)
          AddChildNode(SystemNode[SystemID_Number]);
          ParentNode:= Node;
          mParent:= Node.Index;
        end;
      3: // grouped + system
        begin
          case GameIsClone(mClone) of
             True:
               begin
                 if mParent <> -1 then
                    Node:= GamesTreeView.AddChild(ParentNode)
                 else
                    GenerateMessage('Error', 'This is a clone and the parent is not added yet!!!'+#13#10+
                                    'name: '+mName+#13#10+'clone of: '+mClone, 2);
               end;
             False:
               begin
                 AddChildNode(SystemNode[SystemID_Number]);
                 ParentNode:= Node;
                 mParent:= Node.Index;
               end;
           end;
        end;
    end;

    GameInfoData:= GamesTreeView.GetNodeData(Node);
    GamesTreeView.Expanded[ParentNode]:= ButtonGroupedToggleExpandedClosed.Checked;
    GameInfoData.eImageIndex:= mImageIndex;
    GameInfoData.eParent:= mParent;
    GameInfoData.eROMIdentification:= mROMIdentification;
    GameInfoData.eMediaType:= mMediaType;
    GameInfoData.eIconLoaded:= False;
    GameInfoData.eDescription:= mDescription;
    GameInfoData.eYear:= mYear;
    GameInfoData.eManufacturer:= mManufacturer;
    GameInfoData.eAudioChannels:= mAudioChannels;
    GameInfoData.eAudioSamples:= mAudioSamples;
    GameInfoData.eAudioSampleName:= mAudioSampleName;
    GameInfoData.eControls:= mControls;
    GameInfoData.eControlType:= mControlType;
    GameInfoData.eNumberScreens:= NumScr;

    GameInfoData.eScreenType1:= mScreenType1;
    GameInfoData.eScreenRotation1:= mScreenRotation1;
    GameInfoData.eResolutionWidth1:= mResolutionWidth1;
    GameInfoData.eResolutionHeight1:= mResolutionHeight1;
    GameInfoData.eRefreshRate1:= mRefreshRate1;

    GameInfoData.eScreenType2:= mScreenType2;
    GameInfoData.eScreenRotation2:= mScreenRotation2;
    GameInfoData.eResolutionWidth2:= mResolutionWidth2;
    GameInfoData.eResolutionHeight2:= mResolutionHeight2;
    GameInfoData.eRefreshRate2:= mRefreshRate2;

    GameInfoData.eScreenType3:= mScreenType3;
    GameInfoData.eScreenRotation3:= mScreenRotation3;
    GameInfoData.eResolutionWidth3:= mResolutionWidth3;
    GameInfoData.eResolutionHeight3:= mResolutionHeight3;
    GameInfoData.eRefreshRate3:= mRefreshRate3;

    GameInfoData.eScreenType4:= mScreenType4;
    GameInfoData.eScreenRotation4:= mScreenRotation4;
    GameInfoData.eResolutionWidth4:= mResolutionWidth4;
    GameInfoData.eResolutionHeight4:= mResolutionHeight4;
    GameInfoData.eRefreshRate4:= mRefreshRate4;

    GameInfoData.eDriverStatus:= mDriverStatus;
    GameInfoData.eEmulationStatus:= mEmulationStatus;
    GameInfoData.eColorStatus:= mColorStatus;
    GameInfoData.eSoundStatus:= mSoundStatus;
    GameInfoData.eGraphicStatus:= mGraphicStatus;
    GameInfoData.eCocktailStatus:= mCocktailStatus;
    GameInfoData.eProtectionStatus:= mProtectionStatus;

    GameInfoData.eCategory:= mCategory;
    GameInfoData.eVersionAdded:= mVersionAdded;
    GameInfoData.eName:= mName;
    GameInfoData.eClone:= mClone;
    GameInfoData.eDriverName:= mDriverName;
    GameInfoData.eBiosName:= mBiosName;
    GameInfoData.eMerged:= mMerged;
    if mPlayTime <> '' then
       begin
         GameInfoData.ePlayTimeInteger:= StrToInt64(mPlayTime);
         GameInfoData.ePlayTime:= GetPlayTime(StrToInt64(mPlayTime), True, False);
       end
    else
       begin
         GameInfoData.ePlayTimeInteger:= 0;
         GameInfoData.ePlayTime:= mPlayTime;
       end;
    GameInfoData.ePlayed:= mPlayed;
    GameInfoData.eNumberPlayers:= mNumberPlayers;
    GameInfoData.eGameSize:= mGameSize;
    GameInfoData.eSaveState:= mSaveState;
    if Assigned(GameCPU) and (SystemID_Number in [1, 4, 5, 6]) then
       GameInfoData.eChipCPU:= GameCPU.ReadString(LowerCase(GetSystemIniSection(SystemID_Number)), mName, '');
  end;

  function CheckNewDescription: Boolean;
  begin
    if FormPreferences.NewDescriptionFormat.Checked then
       begin
         if (Copy(mDescription, 1, 4) = 'The ') then
            mDescription:= Copy(mDescription, 5, Length(mDescription))+', The'
         else
         if (Copy(mDescription, 1, 3) = 'Le ') then
            mDescription:= Copy(mDescription, 4, Length(mDescription))+', Le';
       end;
  end;

begin
  if (not Assigned(CategoriesList)) and (FileExists(FrontendPath+'ini_files\catver.ini')) then
     CategoriesList:= TMemIniFile.Create(FrontendPath+'ini_files\catver.ini');

  if FormPreferences.EnableGamePlayTime_Played.Checked then
     begin
       if (not Assigned(GamePlayTime)) and (FileExists(FrontendPath+'ini_files\gameplaytime.ini')) then
          GamePlayTime:= TMemIniFile.Create(FrontendPath+'ini_files\gameplaytime.ini');
     end;

  if (not Assigned(iniNumPlayers)) and (FileExists(FrontendPath+'ini_files\nplayers.ini')) then
     begin
       iniNumPlayers:= THashedStringList.Create;
       iniNumPlayers.LoadFromFile(FrontendPath+'ini_files\nplayers.ini');
     end;

  if (not Assigned(GameCPU)) and (FileExists(FrontendPath+'ini_files\cpu.ini')) then
     GameCPU:= TMemIniFile.Create(FrontendPath+'ini_files\cpu.ini');

  // Initialize virtual data
  GamesTreeView.NodeDataSize:= SizeOf(TGameInfo);
  GamesTreeView.RootNodeCount:= 0;
  GamesTreeView.BeginUpdate;

  if ButtonViewMode.Tag in [2, 3] then
     begin
       for Loop:= 1 to MaxArcadeSystems do
       begin
         SystemNode[Loop]:= nil;
         if ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(Loop)) then
            CreateSystemNodes(SystemNode[Loop], Loop);
       end;
     end;

  mParent:= -1; // reset for safety reasons
  for Loop:=0 to CompleteGamesList.Count-1 do
  begin
    ClearMemoryColumnsVariables;
    GetROMFields(CompleteGamesList, Loop);

    mImageIndex:= mROMIdentification;
    GetSystemID(mROMIdentification);

    CheckNewDescription;

    if (mMerged <> '') and ((SystemID_Number in [1, 4, 5, 6])) then
       mMerged:= aMerged;

    if Assigned(CategoriesList) then
       begin
         if mCategory = '' then
            mCategory:= CategoriesList.ReadString('Category', mName, '');
         if SystemID_Number = 1 then
            mVersionAdded:= CategoriesList.ReadString('VerAdded', mName, '');
       end;

    FillGamePlayTime;

    if Assigned(iniNumPlayers) then
       mNumberPlayers:= iniNumPlayers.Values[mName];

    if mControls <> '' then
       mControlType:= StrToInt(MountControlTypesList(mControls, nil, True));

    NumScr:= -1;
    if mRefreshRate1 <> '' then
       NumScr:= 1;
    if mRefreshRate2 <> '' then
       Inc(NumScr);
    if mRefreshRate3 <> '' then
       Inc(NumScr);
    if mRefreshRate4 <> '' then
       Inc(NumScr);

    // add games to treeview
    AddGameTreeView;
  end;

  FreeAndNil(GamePlayTime);
  FreeAndNil(CategoriesList);
  FreeAndNil(iniNumPlayers);
  FreeAndNil(GameCPU);
  FreeAndNil(tempList);

  if ButtonViewMode.Tag in [2, 3] then
     begin
       for Loop:= 1 to MaxArcadeSystems do
       begin
         if SystemNode[Loop] <> nil then
            GamesTreeView.Expanded[SystemNode[Loop]]:= ButtonGroupedToggleExpandedClosed.Checked;
       end;
     end;
  GamesTreeView.EndUpdate;
  GameInfoData:= nil;
  ApplyFilters(FilterName, SelectItem);
  Result:= CheckTotalVisible(GamesTreeView);
end;

function TFormMain.LoadListCPU(BoxHolder: TComboBox): Boolean;
var
  ListCPU, SortedList: THashedStringList;
  Loop: Integer;
  tmpString, StrCPU: String;
begin
  if not FileExists(FrontendPath+'ini_files\cpu.ini') then
     Exit;
  ListCPU:= THashedStringList.Create;
  ListCPU.LoadFromFile(FrontendPath+'ini_files\cpu.ini');
  SortedList:= THashedStringList.Create;
  SortedList.BeginUpdate;
  for Loop:=0 to ListCPU.Count-1 do
  begin
    tmpString:= ListCPU[Loop];
    if (tmpString <> '') and (tmpString[1] <> '[') then
       begin
         StrCPU:= ListCPU.ValueFromIndex[Loop];
         if SortedList.IndexOf(StrCPU) = -1 then
            SortedList.Add(StrCPU);
       end;
  end;
  SortedList.Sort;
  SortedList.EndUpdate;
  FreeAndNil(ListCPU);
  if SortedList.Count > 0 then
     begin
       BoxHolder.Items.BeginUpdate;
       BoxHolder.Clear;
       BoxHolder.Items.Add('[None]');
       BoxHolder.Items.AddStrings(SortedList);
       BoxHolder.Items.EndUpdate;
       BoxHolder.ItemIndex:= 0;
     end;
  FreeAndNil(SortedList);
end;

function TFormMain.MountControlTypesList(const StringHolder: String; ListViewHolder: TListView; GetFirstControlOnly: Boolean = False): String;
var
  TempString: String;
  Loop: Integer;
begin
  Result:= '';
  if StringHolder = '' then
     Exit;

  TempString:= '';
  for Loop:=1 to Length(StringHolder) do
  begin
    if (StringHolder[Loop] = ',') or (Loop = Length(StringHolder)) then
       begin
         if Loop = Length(StringHolder) then
            TempString:= TempString+StringHolder[Loop];
         case GetFirstControlOnly of
           True:
             begin
               Result:= TempString;
               if Result = '' then
                  Result:= '0';
               Break;
             end;
           False:
             begin
               if Result <> '' then
                  Result:= Result+#13#10+aControlType[StrToInt(TempString), 0]
               else
                  Result:= aControlType[StrToInt(TempString), 0];
               if ListViewHolder <> nil then
                  begin
                    with ListViewHolder.Items.Add do
                    begin
                      Caption:= aControlType[StrToInt(TempString), 0];
                      SubItems.Add(TempString);
                    end;
                  end;
             end;
         end;
         TempString:= '';
         //if (Result <> '') and GetFirstControlOnly then
         //   Break;
       end
    else
       TempString:= TempString+StringHolder[Loop];
  end;
end;

{
function TFormMain.MountControlTypesList(StringHolder: String; GetFirstControlOnly: Boolean = False): String;
var
  TempString: String;
  Loop: Integer;
begin
  Result:= '';
  if StringHolder = '' then
     Exit;

  TempString:= '';
  for Loop:=1 to Length(StringHolder) do
  begin
    if (StringHolder[Loop] = ',') or (Loop = Length(StringHolder)) then
       begin
         if Loop = Length(StringHolder) then
            TempString:= TempString+StringHolder[Loop];
         case GetFirstControlOnly of
           True:
             begin
               Result:= TempString;
               if Result = '' then
                  Result:= '0';
               Break;
             end;
           False:
             begin
               if Result <> '' then
                  Result:= Result+#13#10+aControlType[StrToInt(TempString)]
               else
                  Result:= aControlType[StrToInt(TempString)];
             end;
         end;
         TempString:= '';
         //if (Result <> '') and GetFirstControlOnly then
         //   Break;
       end
    else
       TempString:= TempString+StringHolder[Loop];
  end;
end;
}

procedure TFormMain.UpdateProgressLabel(Position, Total: Integer);
begin
  if FormStatus.ProgressBar.MaxValue <> Total then
     FormStatus.ProgressBar.MaxValue:= Total;
  if (Position <> FormStatus.ProgressBar.Tag) or ((Position = 0) and (FormStatus.ProgressBar.Tag = 0)) then
     begin
       FormStatus.ProgressBar.Progress:= Position;
       if FormStatus.ProgressBar.Progress > FormStatus.ProgressBar.MaxValue then
          GenerateMessage('Error', Format('ProgressBar.Position=%u is higher than ProgressBar.Max=%u'+#13#10+
                          'This is not valid!', [FormStatus.ProgressBar.Progress, FormStatus.ProgressBar.MaxValue]), 2);
     end;
end;

procedure TFormMain.UpdateStatusBarGame;
var
  icoIndex: Integer;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if StatusBar_GameName.Visible then
     begin
        if GetGameData(SelectedNode) then
           begin
             FileIcon:= TIcon.Create;
             icoIndex:= GameInfoData.eROMIdentification;
             if IsSystemEntry(GameInfoData.eDriverName) then
                Inc(icoIndex, MaxGameID);
             if IL_StandardIconsLarge.Count > 0 then
                begin
                  if IL_StandardIconsLarge.Count >= GameInfoData.eROMIdentification then
                     begin
                       case FormMain.MenuStatusBarSize.Tag of
                         0: IL_StandardIconsLarge.GetIcon(icoIndex, FileIcon);
                         1: IL_StandardIconsStandard.GetIcon(icoIndex, FileIcon);
                         2: IL_StandardIconsSmall.GetIcon(icoIndex, FileIcon);
                       end;
                     end;
                end;

             if (not FileIcon.Empty) then
                if IL_StatusBar.Count > 0 then
                   IL_StatusBar.ReplaceIcon(0, FileIcon)
                else
                   IL_StatusBar.AddIcon(FileIcon);
             StatusBar_GameName.Caption:= GameInfoData.eName;
           end;
     end;
  if StatusBar_GameSize.Visible then
     StatusBar_GameSize.Caption:= UpdateGameSize;
  FreeAndNil(FileIcon);
end;

// images procedures
procedure TFormMain.SetAspectRatio;
begin
  case PopupImageStretch.Checked of
    True:
      begin
        case PopupImageStretchLarger.Checked of
          True:
            begin
              if (Images.Bitmap.Width > Images.Width) or (Images.Bitmap.Height > Images.Height) then
                 Images.ScaleMode:= smResize
              else
                 Images.ScaleMode:= smNormal;
            end;
          False: Images.ScaleMode:= smResize;
        end;
      end;
    False: Images.ScaleMode:= smNormal;
  end;

  Images.Bitmap.Changed;
  if (PopupImageStretch.Tag = 0) and (GamesTreeView.Tag = 1) then
     FocusGamesList;
end;

procedure TFormMain.UpdateLabelImages;
begin
  if (not MenuShowImages.Checked) then
     Exit;
  if not FormPreferences.CycleImageTypes.Checked then
     begin
       if (Images.Tag < 10) or (Images.Tag = 1)  then
          begin
            if Images.Tag = 1 then
               ButtonPreviousImage.ImageIndex:= 47;
            case ButtonPreviousImage.Tag of
               0: ButtonNextImage.ImageIndex:= 46;
              -1: ButtonNextImage.ImageIndex:= 48;
            end;
          end
       else
       if Images.Tag = 10 then
          ButtonNextImage.ImageIndex:= 48;
       if Images.Tag > 1 then
          ButtonPreviousImage.ImageIndex:= 45;
       ButtonPreviousImage.Tag:= 0;
     end;
  LabelImageNumber.Caption:= Format('Image %.2d', [ImageNumber]);
end;

function TFormMain.GetImageName(GameName: String; ImageIndex: ShortInt; FormatIndex: ShortInt): String;
begin
  case FormatIndex of
    0: // EL Format [elevator0005.png]
      begin
        if ImageIndex = 1 then
           Result:= GameName
        else
           Result:= GameName+Format('%.4u', [ImageIndex-2]);
      end;
    1: Result:= GameName+'\'+Format('%.4u', [ImageIndex-1]); // New Format [elevator\0005.png]
    2:  // Old MAME Format [elev0005.png]
      begin
        if ImageIndex = 1 then
           Result:= GameName
        else
           Result:= Format('%.4s%.4u', [GameName, (ImageIndex-2)]);
      end;
  end;
end;

procedure TFormMain.CycleImageType;
var
  TypeEnabled: Boolean;
begin
  ButtonNextImage.Tag:= 1;
  Images.Hint:= '';
  repeat
    case ButtonImagesViewMode.Tag of
       0: begin
            TypeEnabled:= FormPreferences.EnableGameSnapshots.Checked;
            if TypeEnabled then
               ButtonShowGameSnapshots.Click;
          end;
       1: begin
            TypeEnabled:= FormPreferences.EnableMarquees.Checked;
            if TypeEnabled then
               ButtonShowMarquees.Click;
          end;
       2: begin
            TypeEnabled:= FormPreferences.EnableFlyers.Checked;
            if TypeEnabled then
               ButtonShowFlyers.Click;
          end;
       3: begin
            TypeEnabled:= FormPreferences.EnableCabinets.Checked;
            if TypeEnabled then
               ButtonShowCabinets.Click;
          end;
       4: begin
            TypeEnabled:= FormPreferences.EnableControlPanels.Checked;
            if TypeEnabled then
               ButtonShowControlPanels.Click;
          end;
       5: begin
            TypeEnabled:= FormPreferences.EnableControlPanelLayouts.Checked;
            if TypeEnabled then
               ButtonShowControlPanelLayouts.Click;
          end;
       6: begin
            TypeEnabled:= FormPreferences.EnableSelect.Checked;
            if TypeEnabled then
               ButtonShowSelect.Click;
          end;
       7: begin
            TypeEnabled:= FormPreferences.EnableVersus.Checked;
            if TypeEnabled then
               ButtonShowVersus.Click;
          end;
       8: begin
            TypeEnabled:= FormPreferences.EnableWallpapers.Checked;
            if TypeEnabled then
               ButtonShowWallpapers.Click;
          end;
       9: begin
            TypeEnabled:= FormPreferences.EnableHardware.Checked;
            if TypeEnabled then
               ButtonShowHardware.Click;
          end;
      10: begin
            TypeEnabled:= FormPreferences.EnableCustomImage.Checked;
            if TypeEnabled then
               ButtonShowCustomImage.Click;
          end;
      11: begin
            TypeEnabled:= FormPreferences.EnableTitleSnapshots.Checked;
            if TypeEnabled then
               ButtonShowTitleSnapshots.Click;
          end;
    end;
    if not TypeEnabled then
       begin
         if ButtonImagesViewMode.Tag < 11 then
            ButtonImagesViewMode.Tag:= ButtonImagesViewMode.Tag+1
         else
            ButtonImagesViewMode.Tag:= 0
       end;
  until TypeEnabled = True;
end;

procedure TFormMain.InvertCycleImageType;
var
  TypeEnabled: Boolean;
begin
  ButtonNextImage.Tag:= 1;
  Images.Hint:= '';
  repeat
    case ButtonImagesViewMode.Tag of
       0: begin
            TypeEnabled:= FormPreferences.EnableCustomImage.Checked;
            if TypeEnabled then
               ButtonShowCustomImage.Click;
          end;
       1: begin
            TypeEnabled:= FormPreferences.EnableTitleSnapshots.Checked;
            if TypeEnabled then
               ButtonShowTitleSnapshots.Click;
          end;
       2: begin
            TypeEnabled:= FormPreferences.EnableGameSnapshots.Checked;
            if TypeEnabled then
               ButtonShowGameSnapshots.Click;
          end;
       3: begin
            TypeEnabled:= FormPreferences.EnableMarquees.Checked;
            if TypeEnabled then
               ButtonShowMarquees.Click;
          end;
       4: begin
            TypeEnabled:= FormPreferences.EnableFlyers.Checked;
            if TypeEnabled then
               ButtonShowFlyers.Click;
          end;
       5: begin
            TypeEnabled:= FormPreferences.EnableCabinets.Checked;
            if TypeEnabled then
               ButtonShowCabinets.Click;
          end;
       6: begin
            TypeEnabled:= FormPreferences.EnableControlPanels.Checked;
            if TypeEnabled then
               ButtonShowControlPanels.Click;
          end;
       7: begin
            TypeEnabled:= FormPreferences.EnableControlPanelLayouts.Checked;
            if TypeEnabled then
               ButtonShowControlPanelLayouts.Click;
          end;
       8: begin
            TypeEnabled:= FormPreferences.EnableSelect.Checked;
            if TypeEnabled then
               ButtonShowSelect.Click;
          end;
       9: begin
            TypeEnabled:= FormPreferences.EnableVersus.Checked;
            if TypeEnabled then
               ButtonShowVersus.Click;
          end;
      10: begin
            TypeEnabled:= FormPreferences.EnableWallpapers.Checked;
            if TypeEnabled then
               ButtonShowWallpapers.Click;
          end;
      11: begin
            TypeEnabled:= FormPreferences.EnableHardware.Checked;
            if TypeEnabled then
               ButtonShowHardware.Click;
          end;
      12: begin
            TypeEnabled:= FormPreferences.EnableCustomImage.Checked;
            if TypeEnabled then
               ButtonShowCustomImage.Click;
          end;
    end;
    if not TypeEnabled then
       begin
         if ButtonImagesViewMode.Tag > 0 then
            ButtonImagesViewMode.Tag:= ButtonImagesViewMode.Tag-1
         else
            ButtonImagesViewMode.Tag:= 11;
       end;
  until TypeEnabled = True;
end;

function TFormMain.VerifyZipType(ZipString: String; GetFolder: Boolean; FullZipPath: Boolean = False): String;
begin
  if LowerCase(ExtractFileExt(ZipString)) = '.zip' then
     begin
       case GetFolder of
         True: Result:= ExtractFilePath(ZipString);
         False:
           begin
             case FullZipPath of
               True : Result:= ZipString;
               False: Result:= ExtractFileName(ZipString);
             end;
           end;
       end;
     end
  else
     begin
       case GetFolder of
         True : Result:= ZipString;
         False: Result:= 'dummy.zip';
       end;
     end;
end;

function TFormMain.GetZipFolderFull(FolderType: ShortInt; SystemID: Integer = -1): String;
begin
  case FolderType of
    0..11: Result:= VerifyZipType(imgFolderZipFile[SystemID, FolderType], True);
    30: Result:= VerifyZipType(FormPreferences.MAMu_Icons.Text, True);
    31: Result:= FormPreferences.FolderGamesFAQ.Text;
    32: Result:= FrontendPath+'resources\main_icons\'; // Frontend Icons Folder
    33: Result:= FrontendPath+'resources\gameslist_icons\'; // Default Game Icons
    34: Result:= FrontendPath+'resources\tray_icons\'; // Tray Icons
  end;
  if not (FolderType in [32..34]) then
  if Result <> '' then
     begin
       if Pos(':', Result) = 0 then
          Result:= FrontendPath+Result;
       if Pos('.zip', LowerCase(Result)) = 0 then
          Result:= IncludeTrailingPathDelimiter(Result);
     end;
end;

function TFormMain.GetImageTypeZIPFilename(ImageType: ShortInt; SystemID: Integer = -1): String;
begin
  Result:= VerifyZipType(imgFolderZipFile[SystemID, ImageType], False, True);
  Result:= FullFolderFix(Result);
end;

function TFormMain.SetScreenAspectRatio(ResWidth, resHeight: Integer; out FixedWidth, FixedHeight: Integer): Boolean;
var
  driverPixelX, driverPixelY,
  //snapPixelX, snapPixelY,
  realPixelX, realPixelY,
  aspectX, aspectY: Integer;
  //Position: Integer;
begin
  if not GetGameData(SelectedNode) then
     Exit;
  case GameInfoData.eScreenRotation1 of
    0, 180:
      begin
        driverPixelX:= GameInfoData.eResolutionWidth1;
        driverPixelY:= GameInfoData.eResolutionHeight1;
      end;
    1, 90, 270:
      begin
        driverPixelX:= GameInfoData.eResolutionHeight1;
        driverPixelY:= GameInfoData.eResolutionWidth1;
      end;
  end;
  //snapPixelX:= resWidth;
  //snapPixelY:= resHeight;
  realPixelX:= resWidth;
  realPixelY:= resHeight;
  FixedWidth:= resWidth;
  FixedHeight:= resHeight;
  if ((driverPixelX <> resWidth) and (driverPixelY <> resHeight)) and
     ((resWidth > driverPixelX) or (resHeight > driverPixelY)) then
     begin
       //FixedHeight:= driverPixelY;//realPixelY;
       //FixedWidth:= driverPixelX;//realPixelX;
       Exit;
     end;
  if driverPixelX >= driverPixelY then
     begin
       aspectX:= 4;
       aspectY:= 3;
     end
  else
  if driverPixelX < driverPixelY then
     begin
       aspectX:= 3;
       aspectY:= 4;
     end;
  //if (snapPixelX < 1) or (snapPixelY < 1) then
  //   begin
  //     snapPixelX:= ResWidth;
  //     snapPixelY:= ResHeight;
  //   end;

  if (Round(driverPixelY / 2 ) = realPixelY) and (realPixelX = driverPixelX) then // cropped playchoice, etc
     begin
       // "aquarush 640x240 driver 640x480 enters this case but height is not resized
       if (realPixelX / aspectX) > (realPixelY / (aspectY / 2)) then
          begin
            FixedHeight:= Round((realPixelX / aspectX) * (aspectY / 2));
            FixedWidth:= realPixelX;
          end
       else
          begin
            FixedWidth:= Round((realPixelY / (aspectY / 2)) * aspectX);
            FixedHeight:= realPixelY;
          end;
     end
  else
  if (Round(driverPixelX / 2 ) = realPixelX) and (realPixelY = driverPixelY) then // lode runner, etc
     begin
       if (realPixelX / (aspectX / 2)) > (realPixelY / aspectY) then
          begin
            FixedHeight:= Round((realPixelX / (aspectX / 2)) * aspectY);
            FixedWidth:= realPixelX;
          end
       else
          begin
            FixedWidth:= Round((realPixelY / aspectY) * (aspectX / 2));
            FixedHeight:= realPixelY;
          end;
     end
  else
  if (realPixelX / aspectX) <> (realPixelY / aspectY) then
     begin
       if (realPixelX / aspectX) > (realPixelY / aspectY) then
          begin
             FixedHeight:= Round((realPixelX / aspectX) * aspectY);
             FixedWidth:= realPixelX;
          end
       else
          begin
            FixedWidth:= Round((realPixelY / aspectY) * aspectX);
            FixedHeight:= realPixelY;
          end;
     end;
end;

function TFormMain.LoadImageFromStream(StreamHolder: TMemoryStream; ImageHolder: TImage32; ImageType: ShortInt; ImageFileName: String; ScreenIndex: ShortInt): Boolean;
var
  pngImg: TPNGGraphic;
  bmpImg: TBitmap;
  jpgImg: TJPEGImage;
  gifImg: TGIFGraphic;
  curWidth, curHeight, newWidth, newHeight: Integer;
begin
  Result:= True;
  if Assigned(StreamHolder) then
     StreamHolder.Position:= 0;
  ImageHolder.Bitmap.BeginUpdate;
  case ImageType of
    0: // .png
      begin
        try
          pngImg:= TPNGGraphic.Create;
          case Assigned(StreamHolder) of
            True : pngImg.LoadFromStream(StreamHolder);
            False: pngImg.LoadFromFile(ImageFileName);
          end;
          // new code
          ImageDetails[ScreenIndex].ResolutionX:= pngImg.Width;
          ImageDetails[ScreenIndex].ResolutionY:= pngImg.Height;
          // new code

          bmpImg:= TBitmap.Create;
          bmpIMG.Assign(pngImg);
          if (pngImg.Width <> 1) or (pngImg.Height <> 1) then
             begin
               if PopupImageScreenAspectRatio.Checked then
                  begin
                    if GameInfoData <> nil then
                    begin
                    if ((GameInfoData.eResolutionWidth1 <> -1) and (GameInfoData.eResolutionHeight1 <> -1)) and
                       (Pos('NoSnapshot', ImageFileName) = 0) and
                       (Pos('NoGamesAvailable', ImageFileName) = 0) then
                       begin
                         curWidth:= pngImg.Width;
                         curHeight:= pngImg.Height;
                         SetScreenAspectRatio(pngImg.Width, pngImg.Height, newWidth, newHeight);
                         if (newWidth <> curWidth) or (newHeight <> curHeight) then
                            begin
                              bmpImg.Width:= newWidth;
                              bmpImg.Height:= newHeight;
                              // new code
                              ImageDetails[ScreenIndex].AspectRatioResolutionX:= newWidth;
                              ImageDetails[ScreenIndex].AspectRatioResolutionY:= newHeight;
                              // new code
                              StretchBlt(bmpImg.Canvas.Handle, 0, 0, newWidth, newHeight,
                                         bmpImg.Canvas.Handle, 0, 0, curWidth, curHeight,
                                         SRCCOPY);
                            end;
                       end;
                    end;
                  end;
             end;
          ImageHolder.Bitmap.Assign(bmpImg);
          FreeAndNil(pngImg);
          FreeAndNil(bmpImg);
        except
          ImageHolder.Bitmap.Clear;
          Result:= False;
        end;
        FreeAndNil(pngImg);
      end;
    1: // .jpg
      begin
        try
          jpgImg:= TJPEGImage.Create;
          case Assigned(StreamHolder) of
            True : jpgImg.LoadFromStream(StreamHolder);
            False: jpgImg.LoadFromFile(ImageFileName);
          end;
          ImageDetails[ScreenIndex].ResolutionX:= jpgImg.Width;
          ImageDetails[ScreenIndex].ResolutionY:= jpgImg.Height;
          ImageHolder.Bitmap.Assign(jpgImg);
        except
          ImageHolder.Bitmap.Clear;
          Result:= False;
        end;
        FreeAndNil(jpgImg);
      end;
    2: // .gif
      begin
        try
          gifImg:= TGIFGraphic.Create;
          gifImg.Transparent:= True;
          case Assigned(StreamHolder) of
            True : gifImg.LoadFromStream(StreamHolder);
            False: gifImg.LoadFromFile(ImageFileName);
          end;
          ImageDetails[ScreenIndex].ResolutionX:= gifImg.Width;
          ImageDetails[ScreenIndex].ResolutionY:= gifImg.Height;
          ImageHolder.Bitmap.Assign(gifImg);
        except
          ImageHolder.Bitmap.Clear;
          Result:= False;
        end;
        FreeAndNil(gifImg);
      end;
  end;
  ImageHolder.Bitmap.EndUpdate;
end;

procedure TFormMain.ClearImage;
begin
  Images.Bitmap.Clear;
  Images.Hint:= '';
  LabelImageNumber.Caption:= '';
  LabelImageNumber.Tag:= 0;
end;

procedure TFormMain.ToggleFavoriteLastFilter;
begin
  if LastFilterName = '' then
     begin
       if (SelectedFilterName <> 'favorites') and
          (SelectedFilterName <> '') then
          begin
            LastFilterName:= SelectedFilterName;
            SelectedFilterName:= 'favorites';
            NoScreenshotLoaded:= False;
            SetGameType(SelectedFilterName, False);
          end;
     end
  else
     begin
       if SelectedFilterName = 'favorites' then
          begin
            SelectedFilterName:= LastFilterName;
            LastFilterName:= '';
            NoScreenshotLoaded:= False;
            SetGameType(SelectedFilterName, False);
          end;
     end;
end;

// new screenshot display routine
function TFormMain.DisplayImage(romID: Integer; GameName, CloneGameName: String; ImageHolder: TImage32; ImageType: Integer; CloseZIP: Boolean; ScreenIndex: ShortInt): Boolean;
var
  Folder, ImageName, ELFormat, NewFormat, OldFormat, ImageExt, LastImageFileName: String;
  NothingFound, ZippedImage, ContinueScan: Boolean;
  ImageIndex: Integer;

  ImageStream: TMemoryStream;
  FileContents: Boolean;

  function LoadUnzippedImage(NameString: String): Boolean;
  begin
    ImageDetails[ScreenIndex].FileName:= Folder+NameString+ImageExt;
    ImageDetails[ScreenIndex].Size:= GetFileSize(ImageDetails[ScreenIndex].FileName);
    if ImageExt = '.png' then
       Result:= LoadImageFromStream(ImageStream, ImageHolder, 0, Folder+NameString+ImageExt, ScreenIndex)
    else
    if ImageExt = '.jpg' then
       Result:= LoadImageFromStream(ImageStream, ImageHolder, 1, Folder+NameString+ImageExt, ScreenIndex)
    else
    if ImageExt = '.gif' then
       Result:= LoadImageFromStream(ImageStream, ImageHolder, 2, Folder+NameString+ImageExt, ScreenIndex);
  end;

  function UnzipToMemory: Boolean;
  begin
    ImageStream:= TMemoryStream.Create;
    Result:= UnZipFileMemory(ImageZIP, imgZipContentsFullPath[SystemID_Number].Strings[ImageIndex], ImageStream, ImageIndex);
    case Result of
      True:
        begin
          ImageDetails[ScreenIndex].FileName:= imgZipContentsFullPath[SystemID_Number].Strings[ImageIndex];
          ImageDetails[ScreenIndex].ZipFileName:= ImageZIP;
        end;
      False:
        begin
          GenerateMessage('Error', 'Could not unzip '+imgZipContentsFullPath[SystemID_Number].Strings[ImageIndex]+
                          ' ['+ImageZIP+'] to memory!', 2);
        end;
    end;
  end;

  function SearchImageFile(NameString: String): Boolean;
  begin
    ImageExt:= '.png';
    Result:= FileExists(Folder+NameString+ImageExt);
    if (not Result) and (not (ImageType in [0, 1, 7, 8])) then
       begin
         ImageExt:= '.jpg';
         Result:= FileExists(Folder+NameString+ImageExt);
         if not Result then
            begin
              ImageExt:= '.gif';
              Result:= FileExists(Folder+NameString+ImageExt);
            end;
       end;
    if Result then
       begin
         NothingFound:= False;
         ImageName:= NameString;
       end;
  end;

  function GetZippedImageIndex(NameString: String): Integer;
  begin
    // this will search for full path now due to new gamename\0000.png format!
    Result:= imgZipContentsFullPath[SystemID_Number].IndexOf(NameString+ImageExt);
  end;

  function SearchZippedImageFile(NameString: String): Boolean;
  begin
    ImageExt:= '.png';
    ImageIndex:= GetZippedImageIndex(NameString);
    if (ImageIndex = -1) and (not (ImageType in [0, 1, 7, 8])) then
       begin
         ImageExt:= '.jpg';
         ImageIndex:= GetZippedImageIndex(NameString);
         if ImageIndex = -1 then
            begin
              ImageExt:= '.gif';
              ImageIndex:= GetZippedImageIndex(NameString);
            end;
       end;
    Result:= (ImageIndex > -1);
    if Result then
       begin
         ZippedImage:= True;
         NothingFound:= False;
         ImageName:= NameString;
       end;
  end;

  function IsNoSnapshot: Boolean;
  begin
    Result:= ImageName = 'NoSnapshot';
  end;

  function GenerateMemZIPList: Boolean;
  begin
    if not Assigned(ListROMsName) then
       begin
         ListROMsName:= THashedStringList.Create;
         ListROMsNameFullPath:= THashedStringList.Create;
       end;
    Result:= GetContents(ImageZIP, True, False);
    if Result then
       begin
         imgZipContents[SystemID_Number].Clear;
         imgZipContentsFullPath[SystemID_Number].Clear;
         imgZipContents[SystemID_Number].AddStrings(ListROMsName);
         imgZipContentsFullPath[SystemID_Number].AddStrings(ListROMsNameFullPath);
         imgZipContents[SystemID_Number].Insert(0, IntToStr(GetFileSize(ImageZIP)));
         imgZipContentsFullPath[SystemID_Number].Insert(0, imgZipContents[SystemID_Number].Strings[0]);
       end;
  end;

begin
  // 01. search old image format unzipped
  // 02. search new image format unzipped
  // 03. search old MAME short format unzipped
  // 04. search old image format zipped
  // 05. search new image format zipped
  // 06. search old MAME short format zipped
  // 07. search clone old image format unzipped
  // 08. search clone new image format unzipped
  // 09. search clone old MAME short format unzipped
  // 10. search clone old image format zipped
  // 11. search clone new image format zipped
  // 12. search clone old MAME short format zipped
  
  Result:= False;
  ContinueScan:= True;
  if (not MenuImagesELFormat.Checked) and (not MenuImagesOldFormat.Checked) and (not MenuImagesNewFormat.Checked) then
     begin
       GenerateMessage('Error', 'All image formats are disabled. Please select at least one format to view images!', 2);
       NoScreenshotLoaded:= False;
       ContinueScan:= False;
     end;
  NothingFound:= True;
  ZippedImage:= False;
  LastImageFileName:= ImageDetails[ScreenIndex].FileName;
  ClearImageInfo(ScreenIndex);

  GetSystemID(romID);
  if ImageType = -1 then
     begin
       Folder:= FrontendPath+'resources\images\';
       ImageZIP:= '';
     end
  else
     begin
       Folder:= GetZipFolderFull(ImageType, SystemID_Number);
       ImageZIP:= GetImageTypeZIPFilename(ImageType, SystemID_Number);
     end;

  ELFormat:= GetImageName(GameName, ImageNumber, 0);
  NewFormat:= GetImageName(GameName, ImageNumber, 1);
  OldFormat:= GetImageName(GameName, ImageNumber, 2);

  if ContinueScan and MenuImagesELFormat.Checked then
     ContinueScan:= not SearchImageFile(ELFormat);

  if ContinueScan and MenuImagesNewFormat.Checked then
     ContinueScan:= not SearchImageFile(NewFormat);
     
  if ContinueScan and MenuImagesOldFormat.Checked then
     ContinueScan:= not SearchImageFile(OldFormat);

  if ContinueScan and (ImageType <> -1) then
     begin
       case FileExists(ImageZIP) of
         True:
           begin
             if not Assigned(imgZipContents[SystemID_Number]) then
                begin
                  imgZipContents[SystemID_Number]:= THashedStringList.Create;
                  imgZipContentsFullPath[SystemID_Number]:= THashedStringList.Create;
                end;
             if imgZipContents[SystemID_Number].Count = 0 then
                FileContents:= GenerateMemZIPList
             else
                begin
                  if imgZipContents[SystemID_Number].Strings[0] <> IntToStr(GetFileSize(ImageZIP)) then
                     FileContents:= GenerateMemZIPList
                  else
                     FileContents:= True;
                end;

             if FileContents then
                begin
                   if MenuImagesELFormat.Checked and ContinueScan then
                      begin
                        ContinueScan:= not SearchZippedImageFile(ELFormat);
                        if not ContinueScan then
                           UnzipToMemory;
                      end;

                   if MenuImagesNewFormat.Checked and ContinueScan then
                      begin
                        ContinueScan:= not SearchZippedImageFile(NewFormat);
                        if not ContinueScan then
                           UnzipToMemory;
                      end;

                   if MenuImagesOldFormat.Checked and ContinueScan then
                      begin
                        ContinueScan:= not SearchZippedImageFile(OldFormat);
                        if not ContinueScan then
                           UnzipToMemory;
                      end;

                   if ContinueScan and PopupImageDisplayParent.Checked then
                      begin
                        if GameIsClone(CloneGameName) then
                           begin
                             ELFormat:= GetImageName(CloneGameName, ImageNumber, 0);
                             NewFormat:= GetImageName(CloneGameName, ImageNumber, 1);
                             OldFormat:= GetImageName(CloneGameName, ImageNumber, 2);

                             if MenuImagesELFormat.Checked then
                                ContinueScan:= not SearchImageFile(ELFormat);

                             if ContinueScan and MenuImagesNewFormat.Checked then
                                ContinueScan:= not SearchImageFile(NewFormat);

                             if ContinueScan and MenuImagesOldFormat.Checked then
                                ContinueScan:= not SearchImageFile(OldFormat);

                             if MenuImagesELFormat.Checked and ContinueScan then
                                begin
                                  if ContinueScan then
                                     ContinueScan:= not SearchZippedImageFile(ELFormat);
                                  if not ContinueScan then
                                     UnzipToMemory;
                                end;

                             if MenuImagesNewFormat.Checked and ContinueScan then
                                begin
                                  if ContinueScan then
                                     ContinueScan:= not SearchZippedImageFile(NewFormat);
                                  if not ContinueScan then
                                     UnzipToMemory;
                                end;

                             if MenuImagesOldFormat.Checked and ContinueScan then
                                begin
                                  ContinueScan:= not SearchZippedImageFile(OldFormat);
                                  if not ContinueScan then
                                     UnzipToMemory;
                                end;
                           end;
                      end;
                end;
           end;
         False:
           begin
             FreeAndNil(imgZipContents[SystemID_Number]);
             FreeAndNil(imgZipContentsFullPath[SystemID_Number]);
             // viewing a clone game... will search for its parent image
             if PopupImageDisplayParent.Checked then
                begin
                  if GameIsClone(CloneGameName) then
                     begin
                       ELFormat:= GetImageName(CloneGameName, ImageNumber, 0);
                       NewFormat:= GetImageName(CloneGameName, ImageNumber, 1);
                       OldFormat:= GetImageName(CloneGameName, ImageNumber, 2);

                       if ContinueScan and MenuImagesELFormat.Checked then
                          ContinueScan:= not SearchImageFile(ELFormat);

                       if ContinueScan and MenuImagesNewFormat.Checked then
                          ContinueScan:= not SearchImageFile(NewFormat);

                       if ContinueScan and MenuImagesOldFormat.Checked then
                          ContinueScan:= not SearchImageFile(OldFormat);
                     end;
                end;
           end;
       end;
     end;

  case NothingFound of
    True:
      begin
        if not NoScreenshotLoaded then
           begin
             Folder:= FrontendPath+'resources\images\';
             ImageExt:= '.png';
             ImageName:= 'NoSnapshot';
             NothingFound:= False;
             NoScreenshotLoaded:= True;
             if LabelImageNumber.Tag = 0 then
                ButtonNextImage.Tag:= 1;
           end;
      end;
    False:
      begin
        NoScreenshotLoaded:= False;
      end;
  end;

  if (not NothingFound) then
     begin
       if not (ImageHolder.Bitmap.DrawMode = dmOpaque) then
          ImageHolder.Bitmap.DrawMode:= dmOpaque;
       case ZippedImage of
         True:
           begin
             if ImageStream.Size > 0 then
                begin
                  if ImageExt = '.png' then
                     Result:= LoadImageFromStream(ImageStream, ImageHolder, 0, '', ScreenIndex)
                  else
                  if ImageExt = '.jpg' then
                     Result:= LoadImageFromStream(ImageStream, ImageHolder, 1, '', ScreenIndex)
                  else
                  if ImageExt = '.gif' then
                     Result:= LoadImageFromStream(ImageStream, ImageHolder, 2, '', ScreenIndex);
                  ImageHolder.Tag:= ImageNumber;
                end
             else
                begin
                  ImageHolder.Bitmap.BeginUpdate;
                  ImageHolder.Bitmap.Clear;
                  ImageHolder.Hint:= 'Zipped image file not found';
                  ImageHolder.Bitmap.EndUpdate;
                end;
           end;
         False:
           begin
             case FileExists(Folder+ImageName+ImageExt) of
               True:
                 begin
                   case IsNoSnapshot of
                     True:
                       begin
                         if ImageNumber = 1 then
                            Result:= LoadUnzippedImage(ImageName);
                       end;
                     False: Result:= LoadUnzippedImage(ImageName);
                   end;
                 end;
               False:
                 begin
                   if ImageNumber > 1 then
                      Result:= False
                   else
                      begin
                        ImageHolder.Bitmap.BeginUpdate;
                        ImageHolder.Bitmap.Clear;
                        ImageHolder.Hint:= Format('File "%s" not found', [Folder+ImageName+ImageExt]);
                        ImageHolder.Tag:= ImageNumber;
                        ImageHolder.Bitmap.EndUpdate;
                        Result:= False;
                      end;
                 end;
             end;
           end;
       end;
       if Result then
          ImageHolder.Tag:= ImageNumber;
       ImageHolder.Bitmap.BeginUpdate;
       if not (ImageHolder.Bitmap.DrawMode = dmBlend) then
          ImageHolder.Bitmap.DrawMode:= dmBlend;

       if (ImageHolder.Bitmap.Width <> 1) or (ImageHolder.Bitmap.Height <> 1) then
          SetAspectRatio;
       ImageHolder.Bitmap.EndUpdate;
       ImageHolder.Bitmap.Changed;
     end
  else
     Result:= False;

  if CloseZIP then
     begin
       FreeAndNil(ListROMsName);
       FreeAndNil(ListROMsNameFullPath);
     end;
  FreeAndNil(ImageStream);
  SetCurrentDir(FrontendPath);
end;
// new screenshot display routine

function TFormMain.FoundMerged(GameName, OriginalGameName, FilePath: String): Boolean;
var
  Loop, FileCounter, CRCNumber: Integer;
  PathString, FixedCRCHex: String;
  Continue: Boolean;
begin
  Result:= False;
  FileCounter:= 0;

  if FilePath = '' then
     PathString:= SearchZIPFolder(OriginalGameName, mROMIdentification)
  else
     PathString:= FilePath;
  if PathString <> '' then
     begin
       Continue:= ParentListROMsName.Count > 0;
       if not Continue then
          begin
            Continue:= GetContents(PathString, False, True);
            Continue:= ParentListROMsName.Count > 0;
          end;
       Result:= Continue;
       if Continue then
          begin
            for Loop:=0 to ListROMsCRC.Count-1 do
            begin
              if Length(ListROMsCRC[Loop]) > 8 then
                 Inc(FileCounter)
              else
              if ((ListROMsCRC[Loop] <> '') and (Length(ListROMsCRC[Loop]) < 10)) then
                 begin
                   CRCNumber:= StrToInt('$'+ListROMsCRC[Loop]);
                   FixedCRCHex:= LowerCase(Format('%.8x', [CRCNumber]));
                   if ParentListROMsCRC.IndexOf(FixedCRCHex) > -1 then
                      Inc(FileCounter);
                 end
              else
                 begin
                   if ParentListROMsCRC.IndexOf(ListROMsCRC[Loop]) > -1 then
                      Inc(FileCounter);
                 end;
            end;
            Result:= (FileCounter = ListROMsName.Count);
          end;
     end;
end;

procedure TFormMain.CallRefreshGames(RefreshMode: ShortInt; CreatingList: Boolean; sysID: Integer);
var
  {StartClock, }NumGamesChanged: Integer;
  Loop, CurrentProgress, TotalProgress: Integer;
  UpdateList: Boolean;
  tmpString, FileGames, FileROMs: String;

  function RefreshGamesCanceledMessage: Boolean;
  begin
    GenerateMessage('Operation Canceled', 'Scan games list is canceled!', 2);
  end;

  function CheckSystemROM_ID: Boolean;
  begin
    Result:= (RefreshMode = 0) or
       // MAME
       ((RefreshMode = 2) and (mROMIdentification in [03..05])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [00..02])) or // have
       // ZiNc
       ((RefreshMode = 2) and (mROMIdentification in [08, 09])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [06, 07])) or // have
       // Daphne
       ((RefreshMode = 2) and (mROMIdentification in [12, 13])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [10, 11])) or // have
       // AGEMAME
       ((RefreshMode = 2) and (mROMIdentification in [17..19])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [14..16])) or // have
       // PinMAME
       ((RefreshMode = 2) and (mROMIdentification in [23..25])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [20..22])) or // have
       // HazeMD
       ((RefreshMode = 2) and (mROMIdentification in [28, 29])) or // miss
       ((RefreshMode = 1) and (mROMIdentification in [26, 27]));   // have
  end;

  procedure FreeMemoryVars;
  begin
    FreeAndNil(FullList);
    FreeAndNil(ListROMs);
    FreeAndNil(ListROMsName);
    FreeAndNil(ListROMsSize);
    FreeAndNil(ListROMsCRC);
    FreeAndNil(ParentListROMsName);
    FreeAndNil(ParentListROMsSize);
    FreeAndNil(ParentListROMsCRC);
    SetCurrentDir(FrontendPath);
  end;

begin
  //StartClock:= GetTickCount();
  FileGames:= GetSystemFileName(sysID);
  if sysID in [1, 4, 5, 6] then
     FileROMs:= GetSystemROMFileName(sysID);

  case sysID of
    1, 4, 5, 6:
      begin
        if (not Check_ROMsData_File(sysID)) or (EmulatorFile[sysID] = '') then
           Exit;
      end;
    2, 3:
      begin
        if (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+FileGames)) or (EmulatorFile[sysID] = '') then
           Exit;
      end;
  end;

  if RefreshMode <> 3 then
     begin
       FormStatus.Show;
       FormStatus.KeyPreview:= True;
     end;

  case RefreshMode of
    0: FormStatus.LabelStatusType.Caption:= 'Scan Games';
    1: FormStatus.LabelStatusType.Caption:= 'Scan Available Games';
    2: FormStatus.LabelStatusType.Caption:= 'Scan Missing Games';
  end;

  if (RefreshMode <> 3) and
     (not (sysID in [2, 3])) then
     begin
       CoolTrayIcon.IconVisible:= True;
       CoolTrayIcon.ShowBalloonHint(FormStatus.LabelStatusType.Caption+
                                    ' ['+GetSystemIniSection(sysID)+']', 'Searching for games. If you have lots of '+
                                    'merged games, this will take some time.', bitInfo, 20);
     end;

  NumGamesChanged:= 0;
  SetCurrentDir(ExtractFilePath(EmulatorFile[sysID]));
  UpdateList:= False;
  if RefreshMode <> 3 then
     begin
       FormStatus.LabelMessage.Caption:= 'Loading files to memory.';
       FormStatus.Refresh;
     end;
  FullList:= THashedStringList.Create;
  FullList.LoadFromFile(FrontendPath+GetMachineTypeGamesFolder+FileGames);
  TotalProgress:= FullList.Count-3;
  if (FileROMs <> '') and
     (FileExists(FrontendPath+GetMachineTypeGamesFolder+FileROMs)) then
     ListROMs:= TMemIniFile.Create(FrontendPath+GetMachineTypeGamesFolder+FileROMs);

  FormStatus.ProgressBar.Tag:= 0;
  CurrentProgress:= 0;
  if RefreshMode <> 3 then
     begin
       FormStatus.LabelMessage.Caption:= 'Verifying '+GetSystemIniSection(sysID)+
                                         ' games.';
       FormStatus.LabelMessage.Refresh;
     end;
  FullList.BeginUpdate;

  case RefreshMode of
    0..2: // multiple games
      begin
        for Loop:= 3 to FullList.Count -1 do
        begin
          tmpString:= FullList[Loop];
          if (tmpString <> '') and (tmpString[1] <> '[') then
             begin
               GetROMFields(FullList, Loop);
               if CheckSystemROM_ID then
                  begin
                    if RefreshGames(FullList, Loop) then
                       begin
                         Inc(NumGamesChanged);
                         UpdateList:= True;
                       end;
                    Application.ProcessMessages;
                    if StopRefreshAllGames then
                       begin
                         FreeMemoryVars;
                         RefreshGamesCanceledMessage;
                         if CoolTrayIcon.IconVisible then
                            CoolTrayIcon.IconVisible:= False;
                         Exit;
                       end;
                  end;
             end;
          Inc(CurrentProgress);
          UpdateProgressLabel(CurrentProgress, TotalProgress);
        end;
      end;
    3: // single game
      begin
        Loop:= GetGameInfo(GameInfoData.eName, FullList);
        if Loop <> -1 then
           begin
             if RefreshGames(FullList, Loop, True) then
                UpdateList:= True;
           end;
      end;
  end;
  FullList.EndUpdate;
  if UpdateList then
     begin
       if RefreshMode <> 3 then
          begin
            case sysID of
              1: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_MAME');
              2: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_ZiNc');
              3: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_Daphne');
              4: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_AGEMAME');
              5: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_PinMAME');
              6: FormStatus.LabelMessage.Caption:= GetStatusMessage('Save_HazeMD');
            end;
            FormStatus.LabelMessage.Refresh;
          end;
       FullList.SaveToFile(FrontendPath+GetMachineTypeGamesFolder+FileGames);
     end;
  FreeMemoryVars;
  //ShowMessage(IntToStr(GetTickCount-StartClock));

  if RefreshMode <> 3 then
     FormStatus.ProgressBar.Tag:= 0;
  if GamesTreeView.Tag = 1 then
     begin
       case CreatingList of
         True: SetGameType(SelectedFilterName, True);
         False:
           begin
             case RefreshMode of
               0..2:
                 begin
                   if NumGamesChanged <> 0 then
                      SetGameType(SelectedFilterName, True);
                 end;
               3:
                 begin
                   if UpdateList then
                      begin
                        GameInfoData.eROMIdentification:= mROMIdentification;
                        if sysID in [1, 4, 5, 6] then
                          begin
                             // MAME / AGEMAME / PinMAME / HazeMD
                             if mMerged <> '' then
                                GameInfoData.eMerged:= aMerged
                             else
                                GameInfoData.eMerged:= '';
                           end;

                        GameInfoData.eAudioSamples:= mAudioSamples;
                        if not PopupGamesUseMAMu_Icons.Checked then
                           begin
                             GameInfoData.eImageIndex:= mROMIdentification;
                             GamesTreeView.Refresh;
                           end;
                        if PopupShowMiss.Checked or PopupShowHave.Checked then
                           SetGameType(SelectedFilterName, False);
                        UpdateStatusBarGame;
                      end;
                 end;
             end;
           end;
       end;
     end;
  if RefreshMode <> 3 then
     begin
       FormStatus.KeyPreview:= False;
       FormStatus.Close;
     end;
  if CoolTrayIcon.IconVisible then
     CoolTrayIcon.IconVisible:= False;
  ShowZipErrors;
end;

function TFormMain.SearchSampleZip(GameName, SampleName: String; sysID: ShortInt): Boolean;
begin
  Result:= FileExists(samplesDir[sysID]+'\'+SampleName+'.zip');
  if not Result then
     begin
       if SampleName <> GameName then
          Result:= FileExists(samplesDir[sysID]+'\'+GameName+'.zip');
     end;
end;

function TFormMain.UpdateSampleInfo(GameName, SampleName: String; sysID: ShortInt): Boolean;
begin
  Result:= False;
  if mAudioSamples <> -1 then
     begin
       case SearchSampleZip(GameName, SampleName, sysID) of
         True:
           begin
             if mAudioSamples = 0 then
                begin
                  Result:= True;
                  mAudioSamples:= 1;
                end;
           end;
         False:
           begin
             if mAudioSamples = 1 then
                begin
                  Result:= True;
                  mAudioSamples:= 0;
                end;
           end;
       end;
     end;
end;

function TFormMain.Check_ROMsData_File(SystemID: Integer): Boolean;
var
  fROM: Boolean;
  romsFile: String;
begin
  if SystemID in [1, 4, 5, 6] then
     romsFile:= GetSystemROMFileName(SystemID)
  else
     romsFile:= '';

  fROM:= romsFile <> '';
  if fROM then
     fROM:= FileExists(FrontendPath+GetMachineTypeGamesFolder+romsFile);
  case fROM of
    True:
      begin
        fROM:= GetFileSize(FrontendPath+GetMachineTypeGamesFolder+romsFile) > 0;
        if not fROM then
           GenerateMessage('Error', 'File "'+FrontendPath+GetMachineTypeGamesFolder+romsFile+'" is empty! Operation aborted...', 2);
      end;
    False:
      begin
        if romsFile <> '' then
           GenerateMessage('Error', 'File "'+FrontendPath+GetMachineTypeGamesFolder+romsFile+'" was not found! Operation aborted...', 2)
        else
           fROM:= True;
      end;
  end;
  Result:= fROM;
end;

function TFormMain.RefreshGames(GamesList1: THashedStringList; GamesList1Position: Integer; SingleGame: Boolean = False): Boolean;
var
  GameFound, GameFoundMerged, ChangeGameStatus, FoundSamples: Boolean;
  ROMDataLine, CloneZIPFolder: String;
  gameFilesList: THashedStringList;

  procedure UpdateGameInfo;
  begin
    ChangeGameStatus:= False;
    ROMDataLine:= PopulateROMDataLine;
    GamesList1[GamesList1Position]:= mName+'='+ROMDataLine;
  end;

begin
  ChangeGameStatus:= True;
  Result:= True;

  GetSystemID(mROMIdentification);
  if SystemID_Number in [1, 4, 5, 6] then
     FoundSamples:= UpdateSampleInfo(mName, mAudioSampleName, SystemID_Number);

  GameFound:= SearchZIP(mName, mROMIdentification);
  if not SingleGame then
     begin
       if not GameIsClone(mClone) then
          begin
            FreeAndNil(ParentListROMsName);
            FreeAndNil(ParentListROMsSize);
            FreeAndNil(ParentListROMsCRC);
          end;
     end;
  case GameFound of
    True: GameFoundMerged:= False;
    False:
      begin
        if SystemID_Number in [1, 4, 5, 6] then
           begin
             case GameIsClone(mClone) of
               True:
                begin
                  CloneZIPFolder:= SearchZIPFolder(mClone, mROMIdentification);
                  if CloneZIPFolder <> '' then
                     begin
                       // get list of files from mName game
                       if not Assigned(ListROMsName) then
                          begin
                            ListROMsName:= THashedStringList.Create;
                            ListROMsSize:= THashedStringList.Create;
                            ListROMsCRC:= THashedStringList.Create;
                          end;

                       if not Assigned(ParentListROMsName) then
                          begin
                            ParentListROMsName:= THashedStringList.Create;
                            ParentListROMsSize:= THashedStringList.Create;
                            ParentListROMsCRC:= THashedStringList.Create;
                          end;

                       gameFilesList:= THashedStringList.Create;
                       ListROMs.ReadSectionValues(mName, gameFilesList);
                       GetGameROMs(gameFilesList, False);
                       FreeAndNil(gameFilesList);

                       // get list of files from mclone .zip
                       // single game... always
                       // multiple games... only if previous game was a parent
                       GameFoundMerged:= FoundMerged(mName, mClone, CloneZIPFolder);

                       FreeAndNil(ListROMsName);
                       FreeAndNil(ListROMsSize);
                       FreeAndNil(ListROMsCRC);
                     end
                  else
                     GameFoundMerged:= False;
                end;
               False: GameFoundMerged:= False;
             end;
           end
        else
           GameFoundMerged:= False;
      end;
  end;
  case GameFound of
    True:
      begin
        case mROMIdentification of
          03: mROMIdentification:= 00; // MAME Master
          04: mROMIdentification:= 01; // MAME Clone
          05: mROMIdentification:= 02; // MAME Bios

          08: mROMIdentification:= 06; // ZiNc Master
          09: mROMIdentification:= 07; // ZiNc Clone

          12: mROMIdentification:= 10; // Daphne Master
          13: mROMIdentification:= 11; // Daphne Clone

          17: mROMIdentification:= 14; // AGEMAME Master
          18: mROMIdentification:= 15; // AGEMAME Clone
          19: mROMIdentification:= 16; // AGEMAME Bios

          23: mROMIdentification:= 20; // PinMAME Master
          24: mROMIdentification:= 21; // PinMAME Clone
          25: mROMIdentification:= 22; // PinMAME Bios

          28: mROMIdentification:= 26; // HazeMD Master
          29: mROMIdentification:= 27; // HazeMD Clone

        else
        if (mMerged = '1') and (SystemID_Number in [1, 4, 5, 6]) then
           begin
             // gamefile was found but here is set as available and merged, so will change only the
             // "Merged" status
             mMerged:= '';
           end
        else
        if (SystemID_Number in [1, 4, 5, 6]) and FoundSamples then
           //UpdateGameInfo
        else
           begin
             ChangeGameStatus:= False;
             Result:= False;
           end;
        end;
      end;
    False:
      begin
        case GameFoundMerged of
          True:
            begin
              mMerged:= '1';
              case mROMIdentification of
                04: mROMIdentification:= 01; // MAME Clone
                18: mROMIdentification:= 15; // AGEMAME Clone
                24: mROMIdentification:= 21; // PinMAME Clone
                29: mROMIdentification:= 27; // HazeMD Clone
              else
              if mMerged = '' then
                 begin
                   // gamefile was found but here is set as available and not merged,
                   // so will change only the "Merged" status
                   mMerged:= '1';
                 end
              else
              if (SystemID_Number in [1, 4, 5, 6]) and FoundSamples then
                 //UpdateGameInfo
              else
                 begin
                   ChangeGameStatus:= False;
                   Result:= False;
                 end;
              end;
            end;
          False:
            begin
              mMerged:= '';
              case mROMIdentification of
                00: mROMIdentification:= 03; // MAME Master
                01: mROMIdentification:= 04; // MAME Clone
                02: mROMIdentification:= 05; // MAME Bios
                06: mROMIdentification:= 08; // ZiNc Master
                07: mROMIdentification:= 09; // ZiNc Clone
                10: mROMIdentification:= 12; // Daphne Master
                11: mROMIdentification:= 13; // Daphne Clone
                14: mROMIdentification:= 17; // AGEMAME Master
                15: mROMIdentification:= 18; // AGEMAME Clone
                16: mROMIdentification:= 19; // AGEMAME Bios
                20: mROMIdentification:= 23; // PinMAME Master
                21: mROMIdentification:= 24; // PinMAME Clone
                22: mROMIdentification:= 25; // PinMAME Bios
                26: mROMIdentification:= 28; // HazeMD Master
                27: mROMIdentification:= 29; // HazeMD Clone
              else
              if (SystemID_Number in [1, 4, 5, 6]) and FoundSamples then
                 //UpdateGameInfo
              else
                 begin
                   ChangeGameStatus:= False;
                   Result:= False;
                 end;
              end;
            end;
        end;
      end;
  end;
  if ChangeGameStatus then
     UpdateGameInfo;
end;

procedure TFormMain.SetCustomOptions(GameName: String; Driver: Boolean);
var
  iniFile: String;
begin
  GetSystemID(GameInfoData.eROMIdentification);
  case SystemID_Number of
    1, 4, 5, 6: // MAME based
      begin
        iniFile:= GetMAMEIniFileName(EmulatorFile[SystemID_Number], SystemID_Number);
        if not Assigned(FormMAMESettings) then
           FormMAMESettings:= TFormMAMESettings.Create(nil);
        LoadMAMESettingsIcons(FormMAMESettings.IL_MAMESettings);
        FormMAMESettings.sysID:= SystemID_Number;
        FormMAMESettings.Tag:= 1; // means custom options

        FormMAMESettings.Caption:= Format('%s Settings',
                 [GetSystemIniSection(SystemID_Number)]);

        case Driver of
          True : FormMAMESettings.Caption:= FormMAMESettings.Caption+' ['+GameInfoData.eDriverName+']';
          False: FormMAMESettings.Caption:= FormMAMESettings.Caption+' ['+GameName+']';
        end;
        FormMAMESettings.Caption:= FormMAMESettings.Caption+' - ['+EmulatorFile[SystemID_Number]+']';

        FormMAMESettings.GameName:= GameName;
        FormMAMESettings.EmulatorString:= EmulatorFile[SystemID_Number];
        FormMAMESettings.emuIni:= iniFile;
        FormMAMESettings.ReadFileIni.Text:= iniFile;
        FormMAMESettings.ReadFile.Hint:= Format('Read "%s.ini"', [iniFile]);
        FormMAMESettings.ShowModal;
        FreeAndNil(FormMAMESettings);
      end;
    2: // ZiNc
      begin
        if not Assigned(FormZiNcSettings) then
           FormZiNcSettings:= TFormZiNcSettings.Create(nil);
        //LoadMAMEConfigurationIcons(FormMAMEConfiguration.IL_MAMEConfig);

        FormZiNcSettings.Tag:= 1; // means custom options
        case Driver of
          True : FormZiNcSettings.Caption:= FormZiNcSettings.Caption+ ' - [driver: '+GameInfoData.eDriverName+']';
          False: FormZiNcSettings.Caption:= FormZiNcSettings.Caption+ ' - ['+GameInfoData.eDescription+']';
        end;

        FormZiNcSettings.zGameName:= GameName;
        FormZiNcSettings.ReadZiNcCFG.Hint:= Format('Read "%s.cfg"', [GetFolderZiNc_cfg+GameName]);
        FormZiNcSettings.ShowModal;
        FreeAndNil(FormZiNcSettings);
      end;
    3: // Daphne
      begin

      end;
  end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.DeleteCustomOptions(GameName: String);
var
  iniFile: String;
begin
  GetSystemID(GameInfoData.eROMIdentification);
  case SystemID_Number of
    1, 4, 5, 6: // MAME based
      begin
        iniFile:= ExtractFilePath(EmulatorFile[SystemID_Number])+IniFilesDir[SystemID_Number]+'\'+GameName+'.ini';
      end;
    2: // ZiNc
      begin
        iniFile:= GetFolderZiNc_cfg+GameName+'.cfg';
      end;
    3: // Daphne
      begin

      end;
  end;
  if GenerateMessage('Delete Custom Initialization File', Format('Delete file "%s". Are you sure ?', [iniFile]), 1) = mrYes then
     DeleteFile(iniFile);
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.UpdateSelectedGamePlayTime(romID: Integer; GameName: String; TotalPlayTime: Int64);
var
  GamePlayTime: TMemIniFile;
  ResultLine, Section, tmpString: String;
  PlayTime: Int64;
  NumPlays: Integer;
  Data: pGameInfo;
begin
  GamesTreeView.BeginUpdate;
  Data:= GamesTreeView.GetNodeData(SelectedNode);
  Data.ePlayed:= Data.ePlayed+1;
  Data.ePlayTimeInteger:= Data.ePlayTimeInteger+TotalPlayTime;
  Data.ePlayTime:= GetPlayTime(Data.ePlayTimeInteger, True, False);
  GamesTreeView.EndUpdate;
  Application.ProcessMessages;

  if CheckReadOnly(FrontendPath+'ini_files\gameplaytime.ini') then
     Exit;
  PlayTime:= 0;
  NumPlays:= 0;
  GamePlayTime:= TMemIniFile.Create(FrontendPath+'ini_files\gameplaytime.ini');
  Section:= GetSystemFolderName(romID);

  GamePlayTime.WriteString(GameName, Section+'_time', IntToStr(Data.ePlayTimeInteger));
  GamePlayTime.WriteString(GameName, Section+'_played', IntToStr(Data.ePlayed));
  GamePlayTime.UpdateFile;
  FreeAndNil(GamePlayTime);
end;

function TFormMain.SetColumnsMemList(IniFileName: TMemIniFile): Boolean;
var
  Loop: Integer;
begin
  SetLength(ColumnsPosList, GamesTreeView.Header.Columns.Count);
  Result:= Length(ColumnsPosList) > 0;
  if not Result then
     begin
       GenerateMessage('Error', 'Could not create temporary list columns indexes. Aborting...', 2);
       Exit;
     end;
  ColumnsPosList[0]:= 0;
  for Loop:=1 to Length(ColumnsPosList)-1 do
      ColumnsPosList[IniFileName.ReadInteger('Position', aColumns[Loop], Loop)]:= Loop;
end;

procedure TFormMain.ReadColumnProfile;
var
  Loop: ShortInt;
  columnFile: TMemIniFile;

  function SetVisibleState(ColumnIndex, IsVisible: ShortInt): Boolean;
  begin
    case Boolean(IsVisible) of
      True : GamesTreeView.Header.Columns.Items[ColumnIndex].Options:= GamesTreeView.Header.Columns.Items[ColumnIndex].Options+[coVisible];
      False: GamesTreeView.Header.Columns.Items[ColumnIndex].Options:= GamesTreeView.Header.Columns.Items[ColumnIndex].Options-[coVisible];
    end;
  end;

begin
  try
    columnFile:= TMemIniFile.Create(GetColumnsProfileFolder+ColumnsProfile[ButtonGameFilterArcade.Tag]);
    if not SetColumnsMemList(columnFile) then
       begin
         FreeAndNil(columnFile);
         Exit;
       end;
    GamesTreeView.BeginUpdate;
    for Loop:=0 to GamesTreeView.Header.Columns.Count-1 do
        GamesTreeView.Header.Columns.Items[Loop].Width:= columnFile.ReadInteger('Width', aColumns[Loop], GamesTreeView.Header.Columns.Items[Loop].Tag);

    for Loop:= 1 to GamesTreeView.Header.Columns.Count-1 do
        SetVisibleState(Loop, columnFile.ReadInteger('Visible', aColumns[Loop], 1));

    for Loop:= 1 to GamesTreeView.Header.Columns.Count-1 do
    begin
      if GamesTreeView.Header.Columns.Items[ColumnsPosList[Loop]].Position <> Loop then
         GamesTreeView.Header.Columns.Items[ColumnsPosList[Loop]].Position:= Loop;
    end;
    for Loop:=0 to Length(ColumnsPosList) do
        Finalize(ColumnsPosList);
    GamesTreeView.EndUpdate;
  finally
    FreeAndNil(columnFile);
  end;
end;

procedure TFormMain.UpdateColumnProfile(UpdateColumns, WriteProfileINI: Boolean);
var
  Loop: ShortInt;
  columnFile: TMemIniFile;
begin
  if UpdateColumns then
     begin
       GamesTreeView.BeginUpdate;

       for Loop:= 0 to FormColumnsEditor.ColumnsList.Items.Count-1 do
       begin
         if GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Position <> Loop then
            GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Position:= Loop;
       end;

       for Loop:= 0 to FormColumnsEditor.ColumnsList.Items.Count-1 do
       begin
         GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Width:= StrToInt(FormColumnsEditor.ColumnsList.Items[Loop].SubItems[0]);
         case FormColumnsEditor.ColumnsList.Items[Loop].Checked of
           True : GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Options:=
                    GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Options+[coVisible];
           False: GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Options:=
                    GamesTreeView.Header.Columns.Items[FormColumnsEditor.ColumnsList.Items[Loop].ImageIndex].Options-[coVisible];
         end;
       end;
       GamesTreeView.EndUpdate;
     end;
  if WriteProfileINI then
     begin
       if ColumnsProfile[ButtonGameFilterArcade.Tag] = '' then
          ColumnsProfile[ButtonGameFilterArcade.Tag]:= 'default.ini';
       if CheckReadOnly(GetColumnsProfileFolder+ColumnsProfile[ButtonGameFilterArcade.Tag]) then
          Exit;
       try
         columnFile:= TMemIniFile.Create(GetColumnsProfileFolder+ColumnsProfile[ButtonGameFilterArcade.Tag]);
         for Loop:=1 to GamesTreeView.Header.Columns.Count-1 do
             columnFile.WriteInteger('Position', aColumns[Loop], GamesTreeView.Header.Columns.Items[Loop].Position);

         for Loop:=0 to GamesTreeView.Header.Columns.Count-1 do
             columnFile.WriteInteger('Width', aColumns[Loop], GamesTreeView.Header.Columns.Items[Loop].Width);

         for Loop:=1 to GamesTreeView.Header.Columns.Count-1 do
             columnFile.WriteInteger('Visible', aColumns[Loop], Ord(coVisible in GamesTreeView.Header.Columns.Items[Loop].Options));

         columnFile.UpdateFile;
       finally
         FreeAndNil(columnFile);
       end;
     end;
end;

// procedures to load icons into TImageList
procedure TFormMain.SetIcon(SourceHolder, DestHolder: TImageList; SourceIndex, DestIndex: Integer);
begin
  if SourceHolder.Height = DestHolder.Height then
     begin
       FileIcon:= TIcon.Create;
       FileIcon.Width:= SourceHolder.Width;
       FileIcon.Height:= SourceHolder.Height;
       FileIcon.Transparent:= True;
       SourceHolder.GetIcon(SourceIndex, FileIcon);
       if not FileIcon.Empty then
          DestHolder.ReplaceIcon(DestIndex, FileIcon);
       FreeAndNil(FileIcon);
     end
  else
     GenerateMessage('Error', 'Icon size of source imagelist and destination imagelist do not match!'+#13#10+
                     'Source: '+SourceHolder.Name+#13#10+'Destination: '+DestHolder.Name, 2);
end;

function TFormMain.GetGameIcon(IL_LargeHolder, IL_StandardHolder, IL_SmallHolder: TImageList; Index: Integer; IconHolder: TIcon): Boolean;
begin
  case PopupGamesUseMAMu_Icons.Checked of
    True:
      begin
        if Index > MaxGameID+(MaxArcadeSystems) then
           begin
             case PopupGameIconSize.Tag of
               0: IL_LargeHolder.GetIcon(Index, IconHolder);
               1: IL_StandardHolder.GetIcon(Index, IconHolder);
               2: IL_SmallHolder.GetIcon(Index, IconHolder);
             end;
           end
        else
           IL_LargeHolder.GetIcon(Index, IconHolder);
      end;
    False: IL_LargeHolder.GetIcon(Index, IconHolder);
  end;
  Result:= not IconHolder.Empty;
end;

procedure TFormMain.LoadFrontendIcons;
begin
  LoadMainScreenIcons;
  LoadStatusBarIcons;
  LoadPreferencesIcons;
  LoadCustomizeColumnsIcons;
  UpdateStatusBarGame;
end;

procedure TFormMain.ClearImageList(IL_Holder: TImageList);
begin
  if IL_Holder.Count > 0 then
     IL_Holder.Clear;
end;

function TFormMain.CheckDefaultIconsFile: Boolean;
var
  FolderIcons: String;
begin
  FolderIcons:= GetZipFolderFull(33);
  Result:= ((FileExists(FolderIcons+'MAMEMaster.ico'))       and
            (FileExists(FolderIcons+'MAMEClone.ico'))        and
            (FileExists(FolderIcons+'MAMEBios.ico'))         and
            (FileExists(FolderIcons+'UnMAMEMaster.ico'))     and
            (FileExists(FolderIcons+'UnMAMEClone.ico'))      and
            (FileExists(FolderIcons+'UnMAMEBios.ico'))       and
            (FileExists(FolderIcons+'ZiNcMaster.ico'))       and
            (FileExists(FolderIcons+'ZiNcClone.ico'))        and
            (FileExists(FolderIcons+'UnZiNcMaster.ico'))     and
            (FileExists(FolderIcons+'UnZiNcClone.ico'))      and
            (FileExists(FolderIcons+'DaphneMaster.ico'))     and
            (FileExists(FolderIcons+'DaphneClone.ico'))      and
            (FileExists(FolderIcons+'UnDaphneMaster.ico'))   and
            (FileExists(FolderIcons+'UnDaphneClone.ico'))    and
            (FileExists(FolderIcons+'AGEMAMEMaster.ico'))    and
            (FileExists(FolderIcons+'AGEMAMEClone.ico'))     and
            (FileExists(FolderIcons+'AGEMAMEBios.ico'))      and
            (FileExists(FolderIcons+'UnAGEMAMEMaster.ico'))  and
            (FileExists(FolderIcons+'UnAGEMAMEClone.ico'))   and
            (FileExists(FolderIcons+'UnAGEMAMEBios.ico'))    and
            (FileExists(FolderIcons+'PinMAMEMaster.ico'))    and
            (FileExists(FolderIcons+'PinMAMEClone.ico'))     and
            (FileExists(FolderIcons+'PinMAMEBios.ico'))      and
            (FileExists(FolderIcons+'UnPinMAMEMaster.ico'))  and
            (FileExists(FolderIcons+'UnPinMAMEClone.ico'))   and
            (FileExists(FolderIcons+'UnPinMAMEBios.ico'))    and
            (FileExists(FolderIcons+'HazeMDMaster.ico'))     and
            (FileExists(FolderIcons+'HazeMDClone.ico'))      and
            (FileExists(FolderIcons+'UnHazeMDMaster.ico'))   and
            (FileExists(FolderIcons+'UnHazeMDClone.ico'))    and

            (FileExists(GetZipFolderFull(32)+'emu_mame.ico'))          and
            (FileExists(GetZipFolderFull(32)+'emu_zinc.ico'))          and
            (FileExists(GetZipFolderFull(32)+'emu_daphne.ico'))        and
            (FileExists(GetZipFolderFull(32)+'emu_agemame.ico'))       and
            (FileExists(GetZipFolderFull(32)+'emu_pinmame.ico'))       and
            (FileExists(GetZipFolderFull(32)+'emu_hazemd.ico'))        and
            (FileExists(GetZipFolderFull(32)+'reserved.ico')));
end;

procedure TFormMain.ReadDefaultIconsFile;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(33);
  AddGameIcons('MAMEMaster.ico', tempFolder);      // 00
  AddGameIcons('MAMEClone.ico', tempFolder);       // 01
  AddGameIcons('MAMEBios.ico', tempFolder);        // 02
  AddGameIcons('UnMAMEMaster.ico', tempFolder);    // 03
  AddGameIcons('UnMAMEClone.ico', tempFolder);     // 04
  AddGameIcons('UnMAMEBios.ico', tempFolder);      // 05
  AddGameIcons('ZiNcMaster.ico', tempFolder);      // 06
  AddGameIcons('ZiNcClone.ico', tempFolder);       // 07
  AddGameIcons('UnZiNcMaster.ico', tempFolder);    // 08
  AddGameIcons('UnZiNcClone.ico', tempFolder);     // 09
  AddGameIcons('DaphneMaster.ico', tempFolder);    // 10
  AddGameIcons('DaphneClone.ico', tempFolder);     // 11
  AddGameIcons('UnDaphneMaster.ico', tempFolder);  // 12
  AddGameIcons('UnDaphneClone.ico', tempFolder);   // 13
  AddGameIcons('AGEMAMEMaster.ico', tempFolder);   // 14
  AddGameIcons('AGEMAMEClone.ico', tempFolder);    // 15
  AddGameIcons('AGEMAMEBios.ico', tempFolder);     // 16
  AddGameIcons('UnAGEMAMEMaster.ico', tempFolder); // 17
  AddGameIcons('UnAGEMAMEClone.ico', tempFolder);  // 18
  AddGameIcons('UnAGEMAMEBios.ico', tempFolder);   // 19
  AddGameIcons('PinMAMEMaster.ico', tempFolder);   // 20
  AddGameIcons('PinMAMEClone.ico', tempFolder);    // 21
  AddGameIcons('PinMAMEBios.ico', tempFolder);     // 22
  AddGameIcons('UnPinMAMEMaster.ico', tempFolder); // 23
  AddGameIcons('UnPinMAMEClone.ico', tempFolder);  // 24
  AddGameIcons('UnPinMAMEBios.ico', tempFolder);   // 25
  AddGameIcons('HazeMDMaster.ico', tempFolder);    // 26
  AddGameIcons('HazeMDClone.ico', tempFolder);     // 27
  AddGameIcons('UnHazeMDMaster.ico', tempFolder);  // 28
  AddGameIcons('UnHazeMDClone.ico', tempFolder);   // 29

  //AddGameIcons('CustomGame.ico', tempFolder);   // 32

  tempFolder:= GetZipFolderFull(32);
  AddGameIcons('emu_mame.ico', tempFolder);      // 30
  AddGameIcons('emu_zinc.ico', tempFolder);      // 31
  AddGameIcons('emu_daphne.ico', tempFolder);    // 32
  AddGameIcons('emu_agemame.ico', tempFolder);   // 33
  AddGameIcons('emu_pinmame.ico', tempFolder);   // 34
  AddGameIcons('emu_hazemd.ico', tempFolder);    // 35
end;

function TFormMain.LoadTrayIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(34);
  Result:= True;
  ClearImageList(IL_TrayIcon);
  AddDefaultIcons('el_icon1.ico', tempFolder, IL_TrayIcon);
  AddDefaultIcons('el_icon2.ico', tempFolder, IL_TrayIcon);
end;

function TFormMain.LoadMainScreenIcons(Reload: Boolean = False): Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  // ViewMode
  ClearImageList(IL_ViewMode_Large);
  if not Reload then
     ClearImageList(IL_ViewMode_Small);
  AddMainScrIcons('viewmode_01_standard.ico', tempFolder, IL_ViewMode_Large, IL_ViewMode_Small, Reload);
  AddMainScrIcons('viewmode_02_grouped.ico', tempFolder, IL_ViewMode_Large, IL_ViewMode_Small, Reload);
  AddMainScrIcons('viewmode_03_system.ico', tempFolder, IL_ViewMode_Large, IL_ViewMode_Small, Reload);
  AddMainScrIcons('viewmode_04_grouped_system.ico', tempFolder, IL_ViewMode_Large, IL_ViewMode_Small, Reload);

  // Arcade Filter
  ClearImageList(IL_ArcadeFilter_Large);
  if not Reload then
     ClearImageList(IL_ArcadeFilter_Small);
  AddMainScrIcons('filterarcade_01_listall.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_02_mame.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_03_zinc.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_04_daphne.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_05_agemame.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_06_pinmame.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);
  AddMainScrIcons('filterarcade_07_hazemd.ico', tempFolder, IL_ArcadeFilter_Large, IL_ArcadeFilter_Small, Reload);

  // Arcade Games Filter
  // ...icons are loaded dynamically

  // Master/Clone Filter
  ClearImageList(IL_FilterMasterClone_Large);
  if not Reload then
     ClearImageList(IL_FilterMasterClone_Small);
  AddMainScrIcons('filter2_01_both.ico', tempFolder, IL_FilterMasterClone_Large, IL_FilterMasterClone_Small, Reload);
  AddMainScrIcons('filter2_02_master.ico', tempFolder, IL_FilterMasterClone_Large, IL_FilterMasterClone_Small, Reload);
  AddMainScrIcons('filter2_03_clone.ico', tempFolder, IL_FilterMasterClone_Large, IL_FilterMasterClone_Small, Reload);

  // Have/Miss Filter
  ClearImageList(IL_FilterHaveMiss_Large);
  if not Reload then
     ClearImageList(IL_FilterHaveMiss_Small);
  AddMainScrIcons('filter3_01_both.ico', tempFolder, IL_FilterHaveMiss_Large, IL_FilterHaveMiss_Small, Reload);
  AddMainScrIcons('filter3_02_have.ico', tempFolder, IL_FilterHaveMiss_Large, IL_FilterHaveMiss_Small, Reload);
  AddMainScrIcons('filter3_03_miss.ico', tempFolder, IL_FilterHaveMiss_Large, IL_FilterHaveMiss_Small, Reload);

  // Working/Non-Working Filter
  ClearImageList(IL_FilterWorkingNonWorking_Large);
  if not Reload then
     ClearImageList(IL_FilterWorkingNonWorking_Small);
  AddMainScrIcons('filter4_01_both.ico', tempFolder, IL_FilterWorkingNonWorking_Large, IL_FilterWorkingNonWorking_Small, Reload);
  AddMainScrIcons('filter4_02_working.ico', tempFolder, IL_FilterWorkingNonWorking_Large, IL_FilterWorkingNonWorking_Small, Reload);
  AddMainScrIcons('filter4_03_nonworking.ico', tempFolder, IL_FilterWorkingNonWorking_Large, IL_FilterWorkingNonWorking_Small, Reload);

  // Number of Screens Filter
  ClearImageList(IL_FilterNumBerScreens_Large);
  if not Reload then
     ClearImageList(IL_FilterNumBerScreens_Small);
  AddMainScrIcons('filter6_numscreens_all.ico', tempFolder, IL_FilterNumberScreens_Large, IL_FilterNumberScreens_Small, Reload);
  AddMainScrIcons('filter6_numscreens_1.ico', tempFolder, IL_FilterNumberScreens_Large, IL_FilterNumberScreens_Small, Reload);
  AddMainScrIcons('filter6_numscreens_2.ico', tempFolder, IL_FilterNumberScreens_Large, IL_FilterNumberScreens_Small, Reload);
  AddMainScrIcons('filter6_numscreens_3.ico', tempFolder, IL_FilterNumberScreens_Large, IL_FilterNumberScreens_Small, Reload);
  AddMainScrIcons('filter6_numscreens_4.ico', tempFolder, IL_FilterNumberScreens_Large, IL_FilterNumberScreens_Small, Reload);

  // Image View Mode Filter
  // ...large icons are loaded dynamically
  
  if not Reload then
     ClearImageList(IL_ImagesViewMode_Small);
  AddDefaultIcons('image_01_titlesnap.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_02_gamesnap.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_03_marquee.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_04_flyer.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_05_cabinet.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_06_cpanel.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_07_cpanellayout.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_08_select.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_09_versus.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_10_wallpaper.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_11_hardware.ico', tempFolder, IL_ImagesViewMode_Small);
  AddDefaultIcons('image_12_custom.ico', tempFolder, IL_ImagesViewMode_Small);

  // Buttons Toolbar 32x32 or 48x48
  ClearImageList(IL_ToolBarButtons);
  AddDefaultIcons('viewmode_01_standard.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filterarcade_01_listall.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('arcade_filters\allgames.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filter2_01_both.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filter3_01_both.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filter4_01_both.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filter5_hidebios.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('filter6_numscreens_all.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('image_02_gamesnap.ico', tempFolder, IL_ToolBarButtons);
  AddDefaultIcons('random_game.ico', tempFolder, IL_ToolBarButtons);

  // Main menu and popup icons
  if not Reload then
    begin
    ClearImageList(IL_MenuPopup);
    AddDefaultIcons('create_gameslist.ico', tempFolder, IL_MenuPopup); // 0
    AddDefaultIcons('settings.ico', tempFolder, IL_MenuPopup); // 1
    AddDefaultIcons('exit.ico', tempFolder, IL_MenuPopup); // 2
    if not AddDefaultIcons(ChangeFileExt(FavoriteUserFile, '.ico'), GetFavoritesFolder, IL_MenuPopup) then
       AddDefaultIcons('default.ico', GetFavoritesFolder, IL_MenuPopup); // 3
    AddDefaultIcons('folder.ico', tempFolder, IL_MenuPopup); // 4
    AddDefaultIcons('binary.ico', tempFolder, IL_MenuPopup); // 5
    AddDefaultIcons('mame_settings.ico', tempFolder, IL_MenuPopup); // 6
    AddDefaultIcons('command_line.ico', tempFolder, IL_MenuPopup); // 7
    AddDefaultIcons('image_view.ico', tempFolder, IL_MenuPopup); // 8
    AddDefaultIcons('password.ico', tempFolder, IL_MenuPopup); // 9
    AddDefaultIcons('columns.ico', tempFolder, IL_MenuPopup); // 10
    AddDefaultIcons('mame_inp_play.ico', tempFolder, IL_MenuPopup); // 11
    AddDefaultIcons('mame_inp_save.ico', tempFolder, IL_MenuPopup); // 12
    AddDefaultIcons('restore_window.ico', tempFolder, IL_MenuPopup); // 13
    AddDefaultIcons('visit_homepage.ico', tempFolder, IL_MenuPopup); // 14
    AddDefaultIcons('send_email.ico', tempFolder, IL_MenuPopup); // 15
    AddDefaultIcons('user_manual.ico', tempFolder, IL_MenuPopup); // 16
    AddDefaultIcons('help.ico', tempFolder, IL_MenuPopup); // 17
    AddDefaultIcons('play_standard.ico', tempFolder, IL_MenuPopup); // 18
    AddDefaultIcons('play_custom.ico', tempFolder, IL_MenuPopup); // 19
    AddDefaultIcons('mame_custom_settings.ico', tempFolder, IL_MenuPopup); // 20
    AddDefaultIcons('options.ico', tempFolder, IL_MenuPopup); // 21 // need to put another icon here
    AddDefaultIcons('delete.ico', tempFolder, IL_MenuPopup); // 22
    AddDefaultIcons('input.ico', tempFolder, IL_MenuPopup); // 23
    AddDefaultIcons('zipfile.ico', tempFolder, IL_MenuPopup); // 24
    AddDefaultIcons('sound.ico', tempFolder, IL_MenuPopup); // 25
    AddDefaultIcons('favorite_user_addgame.ico', tempFolder, IL_MenuPopup); // 26
    AddDefaultIcons('favorite_user_deletegame.ico', tempFolder, IL_MenuPopup); // 27
    AddDefaultIcons('information.ico', tempFolder, IL_MenuPopup); // 28
    AddDefaultIcons('gamedocs.ico', tempFolder, IL_MenuPopup); // 29
    AddDefaultIcons('gamedocs_mameinfo.ico', tempFolder, IL_MenuPopup); // 30
    AddDefaultIcons('gamedocs_history.ico', tempFolder, IL_MenuPopup); // 31
    AddDefaultIcons('gamedocs_driver.ico', tempFolder, IL_MenuPopup); // 32
    AddDefaultIcons('gamedocs_faq.ico', tempFolder, IL_MenuPopup); // 33
    AddDefaultIcons('gamedocs_story.ico', tempFolder, IL_MenuPopup); // 34
    AddDefaultIcons('gameicons_enable.ico', tempFolder, IL_MenuPopup); // 35
    AddDefaultIcons('gameicons_checkmiss.ico', tempFolder, IL_MenuPopup); // 36
    AddDefaultIcons('gameicons_checkunneeded.ico', tempFolder, IL_MenuPopup); // 37

    AddDefaultIcons('refresh_games_have.ico', tempFolder, IL_MenuPopup); // 38
    AddDefaultIcons('refresh_games_miss.ico', tempFolder, IL_MenuPopup); // 39
    AddDefaultIcons('refresh_games_all.ico', tempFolder, IL_MenuPopup); // 40
    AddDefaultIcons('audit_single.ico', tempFolder, IL_MenuPopup); // 41
    AddDefaultIcons('audit_multiple.ico', tempFolder, IL_MenuPopup); // 42
    AddDefaultIcons('image_rename.ico', tempFolder, IL_MenuPopup); // 43
    AddDefaultIcons('image_delete.ico', tempFolder, IL_MenuPopup); // 44
    AddDefaultIcons('image_prev.ico', tempFolder, IL_MenuPopup); // 45
    AddDefaultIcons('image_next.ico', tempFolder, IL_MenuPopup); // 46
    AddDefaultIcons('image_prevno.ico', tempFolder, IL_MenuPopup); // 47
    AddDefaultIcons('image_nextno.ico', tempFolder, IL_MenuPopup); // 48
    AddDefaultIcons('image_prev_type.ico', tempFolder, IL_MenuPopup); // 49
    AddDefaultIcons('image_next_type.ico', tempFolder, IL_MenuPopup); // 50
    AddDefaultIcons('favorite_user_new.ico', tempFolder, IL_MenuPopup); // 51
    AddDefaultIcons('favorite_user_edit.ico', tempFolder, IL_MenuPopup); // 52 // this icon is not needed anymore!!!!
    AddDefaultIcons('favorite_user_delete.ico', tempFolder, IL_MenuPopup); // 53
    AddDefaultIcons('favorite_user_update.ico', tempFolder, IL_MenuPopup); // 54
    AddDefaultIcons('image_flip_horizontal.ico', tempFolder, IL_MenuPopup); // 55
    AddDefaultIcons('image_flip_vertical.ico', tempFolder, IL_MenuPopup); // 56
    AddDefaultIcons('image_rotate.ico', tempFolder, IL_MenuPopup); // 57
    AddDefaultIcons('image_02_gamesnap.ico', tempFolder, IL_MenuPopup); // 58
    AddDefaultIcons('stop.ico', tempFolder, IL_MenuPopup); // 59
    AddDefaultIcons('ctrl_devastator2.ico', tempFolder, IL_MenuPopup); // 60
    AddDefaultIcons('ctrl_hotrod.ico', tempFolder, IL_MenuPopup); // 61
    AddDefaultIcons('ctrl_slikstik.ico', tempFolder, IL_MenuPopup); // 62
    AddDefaultIcons('ctrl_xarcade.ico', tempFolder, IL_MenuPopup); // 63
    AddDefaultIcons('savestate.ico', tempFolder, IL_MenuPopup); // 64
    AddDefaultIcons('bios_chip.ico', tempFolder, IL_MenuPopup); // 65
    AddDefaultIcons('video.ico', tempFolder, IL_MenuPopup); // 66
    AddDefaultIcons('toolbar.ico', tempFolder, IL_MenuPopup); // 67
    AddDefaultIcons('audit.ico', tempFolder, IL_MenuPopup); // 68
    AddDefaultIcons('image.ico', tempFolder, IL_MenuPopup); // 69
    AddDefaultIcons('full_screen.ico', tempFolder, IL_MenuPopup); // 70
    AddDefaultIcons('show_expanded.ico', tempFolder, IL_MenuPopup); // 71
    AddDefaultIcons('autogamedocs_layout_top.ico', tempFolder, IL_MenuPopup); // 72
    AddDefaultIcons('autogamedocs_layout_bottom.ico', tempFolder, IL_MenuPopup); // 73
    AddDefaultIcons('autogamedocs_layout_left.ico', tempFolder, IL_MenuPopup); // 74
    AddDefaultIcons('autogamedocs_layout_right.ico', tempFolder, IL_MenuPopup); // 75
    AddDefaultIcons('autogamedocs_font.ico', tempFolder, IL_MenuPopup); // 76

    // Arcade systems / emulator icons
    ClearImageList(IL_ArcadeSystem_Large);
    ClearImageList(IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_all.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_all.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_mame.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_mame.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_zinc.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_zinc.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_daphne.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_daphne.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_agemame.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_agemame.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_pinmame.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_pinmame.ico', tempFolder, IL_ArcadeSystem_Small);
    AddDefaultIcons('emu_hazemd.ico', tempFolder, IL_ArcadeSystem_Large);
    AddDefaultIcons('emu_hazemd.ico', tempFolder, IL_ArcadeSystem_Small);
  end;
end;

function TFormMain.LoadStatusBarIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  ClearImageList(IL_StatusBar);
  AddDefaultIcons('reserved.ico', tempFolder, IL_StatusBar);
  AddDefaultIcons('statusbar_game_size_emu.ico', tempFolder, IL_StatusBar);
  AddDefaultIcons('statusbar_game_size_zip.ico', tempFolder, IL_StatusBar);
  AddDefaultIcons('statusbar_total_games.ico', tempFolder, IL_StatusBar);
  if not AddDefaultIcons(ChangeFileExt(FavoriteUserFile, '.ico'), GetFavoritesFolder, IL_StatusBar) then
     AddDefaultIcons('default.ico', GetFavoritesFolder, IL_StatusBar);
end;

function TFormMain.LoadMAMESettingsIcons(IconList: TImageList): Boolean;
var
  tempFolder: String;
begin
  ClearImageList(IconList);
  tempFolder:= GetZipFolderFull(32);
  AddDefaultIcons('folder.ico', tempFolder, IconList);
  AddDefaultIcons('settings.ico', tempFolder, IconList);
  AddDefaultIcons('display.ico', tempFolder, IconList);
  AddDefaultIcons('sound.ico', tempFolder, IconList);
  AddDefaultIcons('play_standard.ico', tempFolder, IconList);
  AddDefaultIcons('miscellaneous.ico', tempFolder, IconList);
  Result:= True;
end;

function TFormMain.LoadPreferencesIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  ClearImageList(FormPreferences.IL_Preferences);
  AddDefaultIcons('general.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('appearance.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('ctrl_hotrod.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('ctrl_slikstik.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('ctrl_xarcade.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('miscellaneous.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('play_standard.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('image.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('binary.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('folder.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('multimedia.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('zipfile.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('ctrl_devastator2.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('emu_zinc.ico', tempFolder, FormPreferences.IL_Preferences);
  AddDefaultIcons('emu_daphne.ico', tempFolder, FormPreferences.IL_Preferences);

  FileIcon:= TIcon.Create;
  FileIcon.Transparent:= True;
  FileIcon.Width:= 24;
  FileIcon.Height:= 24;

  IL_ImagesViewMode_Small.GetIcon(0, FileIcon);
  FormPreferences.imgType_TitleSnapshots.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(1, FileIcon);
  FormPreferences.imgType_GameSnapshots.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(2, FileIcon);
  FormPreferences.imgType_Marquees.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(3, FileIcon);
  FormPreferences.imgType_Flyers.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(4, FileIcon);
  FormPreferences.imgType_Cabinets.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(5, FileIcon);
  FormPreferences.imgType_ControlPanels.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(6, FileIcon);
  FormPreferences.imgType_ControlPanelLayouts.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(7, FileIcon);
  FormPreferences.imgType_Select.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(8, FileIcon);
  FormPreferences.imgType_Versus.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(9, FileIcon);
  FormPreferences.imgType_Wallpapers.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(10, FileIcon);
  FormPreferences.imgType_Hardware.Picture.Icon.Assign(FileIcon);

  IL_ImagesViewMode_Small.GetIcon(11, FileIcon);
  FormPreferences.imgType_Custom.Picture.Icon.Assign(FileIcon);
  
  FreeAndNil(FileIcon);
  Result:= True;
end;

function TFormMain.LoadAuditIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  ClearImageList(FormAudit.ImageListResults);
  ClearImageList(FormAudit.ImageListSmallIcons);
  AddDefaultIcons('audit00_good_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit01_good_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit02_good_nodump_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit03_good_nodump_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit04_good_redump_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit05_good_redump_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit06_good_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit07_good_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit08_good_nodump_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit09_good_nodump_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit10_good_redump_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit11_good_redump_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit12_bad_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit13_bad_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit14_bad_nodump_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit15_bad_nodump_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit16_bad_redump_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit17_bad_redump_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit18_bad_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit19_bad_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit20_bad_nodump_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit21_bad_nodump_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit22_bad_redump_m_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit23_bad_redump_m_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit24_notused_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit25_missing_rom.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit26_missing_chd.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit27_game_ok.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit28_game_m_ok.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit29_game_bad.ico', tempFolder, FormAudit.ImageListResults);
  AddDefaultIcons('audit30_game_m_bad.ico', tempFolder, FormAudit.ImageListResults);

  AddDefaultIcons('folder.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('audit_single.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('savetofile.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('statusbar_total_games.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('audit_result_good.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('audit_result_errors.ico', tempFolder, FormAudit.ImageListSmallIcons);
  AddDefaultIcons('audit_result_bad.ico', tempFolder, FormAudit.ImageListSmallIcons);
end;

function TFormMain.LoadParentalLockIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  AddDefaultIcons('search.ico', tempFolder, FormParentalLockEditor.ParentalLockImageList);
  AddDefaultIcons('keylock.ico', tempFolder, FormParentalLockEditor.ParentalLockImageList);
end;

function TFormMain.LoadCustomizeColumnsIcons: Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  AddDefaultIcons('column_00_description.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_01_year.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_02_manufacturer.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_03_audiochannels.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_04_audiosamples.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_05_numscreens.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_06_screentype.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_07_orientation.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_08_resolution.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_09_refreshrate.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_06_screentype.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_07_orientation.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_08_resolution.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_09_refreshrate.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_06_screentype.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_07_orientation.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_08_resolution.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_09_refreshrate.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_06_screentype.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_07_orientation.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_08_resolution.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_09_refreshrate.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_10_driverstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_11_emulationstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_12_colorstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_13_soundstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_14_graphicstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_15_cocktailstatus.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_16_protectionstatus.ico', tempFolder, IL_Columns);

  AddDefaultIcons('column_17_category.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_18_versionadded.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_19_name.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_20_cloneof.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_21_drivername.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_22_merged.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_23_playtime.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_24_played.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_25_numplayers.ico', tempFolder, IL_Columns);
  AddDefaultIcons('column_26_controltype.ico', tempFolder, IL_Columns);
  AddDefaultIcons('savestate.ico', tempFolder, IL_Columns);
end;

function TFormMain.LoadMAMu_SettingsIcons(ImageListHolder: TImageList): Boolean;
var
  tempFolder: String;
begin
  tempFolder:= GetZipFolderFull(32);
  Result:= True;
  ClearImageList(ImageListHolder);
  AddDefaultIcons('column_20_cloneof.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('unzipfile.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('zipfile.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_mame.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_zinc.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_daphne.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_agemame.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_pinmame.ico', tempFolder, ImageListHolder);
  AddDefaultIcons('emu_hazemd.ico', tempFolder, ImageListHolder);
end;

function TFormMain.SetToolBarIcon(IconFileName, IconFolder: String; IconList: TImageList; IconIndex: Integer; DisplayErrorMsg: Boolean = True): Boolean;
var
  Icon32: TExIcon;
  tmpIcon: TIcon;
  icoLoop: ShortInt;
  ColorDepth: TPixelFormat;
  IconLoaded: Boolean;
begin
  Result:= False;
  if not FileExists(IconFolder+IconFileName+'.ico') then
     begin
       if (IconList = IL_StatusBar) and (IconIndex = 4) then
          Exit
       else
          begin
            if DisplayErrorMsg then
               GenerateMessage('Error', 'File "'+IconFolder+IconFileName+'.ico" is missing. Icon cannot be'+
                               'updated.', 2);
            Exit;
          end;
     end;
  Icon32:= TExIcon.Create;
  Icon32.LoadFromFile(IconFolder+IconFileName+'.ico');
  IconLoaded:= False;
  case Use32bitsIcons of
    True : ColorDepth:= pf32bit;
    False: ColorDepth:= pf24bit;
  end;
  for icoLoop:=0 to Icon32.ImageCount-1 do
  begin
    if (Icon32.Images[icoLoop].Width = IconList.Width) and
       (Icon32.Images[icoLoop].Height = IconList.Height) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         Icon32.CurrentImage:= icoLoop;
         tmpIcon:= TIcon.Create;
         tmpIcon.Handle:= Icon32.Handle;
         IconList.ReplaceIcon(IconIndex, tmpIcon);
         FreeAndNil(tmpIcon);
         Result:= True;
         IconLoaded:= True;
         Break;
       end;
  end;
  FreeAndNil(Icon32);
  if not IconLoaded then
     GenerateMessage('Error', 'Tool bar icon ('+IntToStr(IconList.Width)+'x'+
                                             IntToStr(IconList.Height)+') not loaded.'+#13#10+
                     IconFolder+IconFileName, 2);
end;

function TFormMain.AddDefaultIcons(IconFileName, IconsFolder: String; IconList: TImageList): Boolean;
var
  Icon32: TExIcon;
  tmpIcon: TIcon;
  icoLoop: ShortInt;
  ColorDepth: TPixelFormat;
  IconAdded: Boolean;
begin
  Result:= False;
  if not FileExists(IconsFolder+IconFileName) then
     begin
       if IconList.Name <> 'IL_FavoriteProfiles' then
          begin
            if IconFileName <> ChangeFileExt(FavoriteUserFile, '.ico') then
               GenerateMessage('Error', Format(MissingIconFileMsg, [IconsFolder+IconFileName]), 2);
          end;
       Exit;
     end;
  Icon32:= TExIcon.Create;
  Icon32.LoadFromFile(IconsFolder+IconFileName);
  case Use32bitsIcons of
    True : ColorDepth:= pf32bit;
    False:
      begin
        if IconList.Name <> 'IL_TrayIcon' then
           ColorDepth:= pf24bit
        else
           ColorDepth:= pf8bit;
      end;
  end;
  IconAdded:= False;
  for icoLoop:=0 to Icon32.ImageCount-1 do
  begin
    if (Icon32.Images[icoLoop].Width = IconList.Width) and
       (Icon32.Images[icoLoop].Height = IconList.Height) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         Icon32.CurrentImage:= icoLoop;
         tmpIcon:= TIcon.Create;
         tmpIcon.Handle:= Icon32.Handle;
         IconList.AddIcon(tmpIcon);
         tmpIcon.ReleaseHandle;
         FreeAndNil(tmpIcon);
         Result:= True;
         IconAdded:= True;
         Break;
       end;
  end;
  FreeAndNil(Icon32);
  if not IconAdded then
     GenerateMessage('Error', 'Icon ('+IntToStr(IconList.Width)+'x'+
                                       IntToStr(IconList.Height)+') not added.'+#13#10+
                     IconsFolder+IconFileName, 2);
end;

function TFormMain.AddMainScrIcons(IconFileName, IconsFolder: String; IconListLarge, IconListSmall: TImageList; Reload: Boolean): Boolean;
var
  Icon32: TExIcon;
  icoLoop: ShortInt;
  ColorDepth: TPixelFormat;
  LargeIconAdded, SmallIconAdded: Boolean;
  ErrorMsg: String;

  procedure AddIcon(DestImgList: TImageList);
  var
    tmpIcon: TIcon;
  begin
    Icon32.CurrentImage:= icoLoop;
    tmpIcon:= TIcon.Create;
    tmpIcon.Handle:= Icon32.Handle;
    DestImgList.AddIcon(tmpIcon);
    tmpIcon.ReleaseHandle;
    FreeAndNil(tmpIcon);
  end;

begin
  Result:= False;
  if not FileExists(IconsFolder+IconFileName) then
     begin
       GenerateMessage('Error', Format(MissingIconFileMsg, [IconsFolder+IconFileName]), 2);
       Exit;
     end;
  Icon32:= TExIcon.Create;
  Icon32.LoadFromFile(IconsFolder+IconFileName);
  case Use32bitsIcons of
    True : ColorDepth:= pf32bit;
    False: ColorDepth:= pf24bit;
  end;
  LargeIconAdded:= False;
  SmallIconAdded:= Reload;
  for icoLoop:=0 to Icon32.ImageCount-1 do
  begin
    if (Icon32.Images[icoLoop].Width = IconListLarge.Width) and
       (Icon32.Images[icoLoop].Height = IconListLarge.Height) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         AddIcon(IconListLarge);
         LargeIconAdded:= True;
       end
    else
    if (Icon32.Images[icoLoop].Width = 24) and
       (Icon32.Images[icoLoop].Height = 24) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) and
       (not Reload) then
       begin
         AddIcon(IconListSmall);
         SmallIconAdded:= True;
       end;
    if LargeIconAdded and SmallIconAdded then
       begin
         Result:= True;
         Break;
       end;
  end;
  FreeAndNil(Icon32);
  ErrorMsg:= '';
  if not LargeIconAdded then
     ErrorMsg:= 'Large icon ('+IntToStr(IconListLarge.Width)+'x'+
                               IntToStr(IconListLarge.Height)+' not added.'+#13#10+
                IconsFolder+IconFileName;
  if not LargeIconAdded then
     GenerateMessage('Error', 'Large icon ('+IntToStr(IconListLarge.Width)+'x'+
                                             IntToStr(IconListLarge.Height)+') not added.'+#13#10+
                     IconsFolder+IconFileName, 2);
  if not SmallIconAdded then
     begin
       if ErrorMsg <> '' then
          ErrorMsg:= ErrorMsg+#13#10+#13#10;
       ErrorMsg:= 'Small icons (24x24) not added.'+#13#10+IconsFolder+IconFileName;
     end;
  if ErrorMsg <> '' then
     GenerateMessage('Error', ErrorMsg, 2);
end;

function TFormMain.AddGameIcons(IconFileName, IconsFolder: String): Boolean;
var
  Icon32: TExIcon;
  icoLoop: ShortInt;
  ColorDepth: TPixelFormat;
  LargeIconAdded, StandardIconAdded, SmallIconAdded: Boolean;

  procedure AddIcon(DestImgList: TImageList);
  var
    tmpIcon: TIcon;
  begin
    Icon32.CurrentImage:= icoLoop;
    tmpIcon:= TIcon.Create;
    tmpIcon.Width:= DestImgList.Width;
    tmpIcon.Height:= DestImgList.Height;
    tmpIcon.Handle:= Icon32.Handle;
    DestImgList.AddIcon(tmpIcon);
    tmpIcon.ReleaseHandle;
    FreeAndNil(tmpIcon);
  end;

begin
  Result:= False;
  if not FileExists(IconsFolder+IconFileName) then
     begin
       GenerateMessage('Error', Format(MissingIconFileMsg, [IconsFolder+IconFileName]), 2);
       Exit;
     end;
  Icon32:= TExIcon.Create;
  Icon32.LoadFromFile(IconsFolder+IconFileName);
  case Use32bitsIcons of
    True : ColorDepth:= pf32bit;
    False: ColorDepth:= pf24bit;
  end;
  LargeIconAdded:= False;
  StandardIconAdded:= False;
  SmallIconAdded:= False;

  for icoLoop:=0 to Icon32.ImageCount-1 do
  begin
    {if (Icon32.Images[icoLoop].Width = 48) and
       (Icon32.Images[icoLoop].Height = 48) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         AddIcon(IL_StandardIconsTile);
         TileIconAdded:= True;
       end
    else}
    if (Icon32.Images[icoLoop].Width = 32) and
       (Icon32.Images[icoLoop].Height = 32) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         AddIcon(IL_StandardIconsLarge);
         LargeIconAdded:= True;
       end
    else
    if (Icon32.Images[icoLoop].Width = 24) and
       (Icon32.Images[icoLoop].Height = 24) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         AddIcon(IL_StandardIconsStandard);
         StandardIconAdded:= True;
       end
    else
    if (Icon32.Images[icoLoop].Width = 16) and
       (Icon32.Images[icoLoop].Height = 16) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         AddIcon(IL_StandardIconsSmall);
         SmallIconAdded:= True;
       end;
    if LargeIconAdded and StandardIconAdded and SmallIconAdded then
       begin
         Result:= True;
         Break;
       end;
  end;
  FreeAndNil(Icon32);
  if not LargeIconAdded then
     GenerateMessage('Error', 'Large icon (32x32) not added.'+#13#10+
                     IconsFolder+IconFileName, 2);
  if not StandardIconAdded then
     GenerateMessage('Error', 'Standard icon (24x24) not added.'+#13#10+
                     IconsFolder+IconFileName, 2);
  if not SmallIconAdded then
     GenerateMessage('Error', 'Small icons (16x16) not added.'+#13#10+
                     IconsFolder+IconFileName, 2);
end;

function TFormMain.AddMAMu_Icon(romID: Integer; GameName, CloneName: String; IconList: TImageList): Integer;
var
  Icon32: TIcon;
  System, Folder: String;
  icoIdx: Integer;

  function LoadUnzipped: Boolean;
  begin
    Result:= True;
    case PopupShowParentIconOnly.Checked of
      True:
        begin
          case GameIsClone(CloneName) of
            True:
              begin
                Result:= FileExists(Folder+System+CloneName+'.ico');
                if Result then
                   Icon32.LoadFromFile(Folder+System+CloneName+'.ico');
              end;
            False:
              begin
                Result:= FileExists(Folder+System+GameName+'.ico');
                if Result then
                   Icon32.LoadFromFile(Folder+System+GameName+'.ico')
              end;
          end;
        end;
      False:
        begin
          case FileExists(Folder+System+GameName+'.ico') of
            True: Icon32.LoadFromFile(Folder+System+GameName+'.ico');
            False:
              begin
                if GameIsClone(CloneName) and
                   FileExists(Folder+System+CloneName+'.ico') then
                   Icon32.LoadFromFile(Folder+System+CloneName+'.ico')
                else
                   Result:= False;
              end;
          end;
        end;
    end;
  end;

  function UnzipIco: Boolean;
  begin
    if icoIdx = -1 then
       Result:= False
    else
       begin
         Result:= True;
         try
           icoStream.Clear;
           TZipForgeFriend(ZipForgeMAMu_).ExtractItem(icoIdx, icoStream);
           if icoStream.Size > 0 then
              begin
                icoStream.Position:= 0;
                Icon32.LoadFromStream(icoStream);
              end
           else
              Result:= False;
         except
           Result:= False;
         end;
       end;
  end;

begin
  Result:= -1;
  System:= GetSystemFolderName(romID);
  if System = 'mame' then
     System:= ''
  else
     System:= System+'\';
  Folder:= GetZipFolderFull(30);
  Icon32:= TIcon.Create;
  case PopupGameIconSize.Tag of
    0:
      begin
        Icon32.Width:= 32;
        Icon32.Height:= 32;
      end;
    1:
      begin
        Icon32.Width:= 24;
        Icon32.Height:= 24;
      end;
    2:
      begin
        Icon32.Width:= 16;
        Icon32.Height:= 16;
      end;
  end;
  case Assigned(MAMu_ZipContents) of
    True:
      begin
        case PopupShowParentIconOnly.Checked of
          True:
            begin
              case GameIsClone(CloneName) of
                True:
                  begin
                    icoIdx:= MAMu_ZipContents.IndexOf(System+CloneName+'.ico');
                    if not UnzipIco then
                       LoadUnzipped;
                  end;
                False:
                  begin
                    icoIdx:= MAMu_ZipContents.IndexOf(System+GameName+'.ico');
                    if not UnzipIco then
                       LoadUnzipped;
                  end;
              end;
            end;
          False:
            begin
              icoIdx:= MAMu_ZipContents.IndexOf(System+GameName+'.ico');
              if not UnZipIco then
                 begin
                   case GameIsClone(CloneName) of
                     True:
                       begin
                         icoIdx:= MAMu_ZipContents.IndexOf(System+CloneName+'.ico');
                         if not UnzipIco then
                            LoadUnzipped;
                       end;
                     False: LoadUnzipped;
                   end;
                 end;
            end;
        end;
      end;
    False: LoadUnzipped;
  end;
  if not Icon32.Empty then
     Result:= IconList.AddIcon(Icon32);
  FreeAndNil(Icon32);
end;

function TFormMain.LoadFavUserIcon128(IconFileName: String; ImageHolder: TImage): Boolean;
var
  Icon32: TExIcon;
  icoLoop: ShortInt;
  ColorDepth: TPixelFormat;
  tmpIcon: TIcon;
begin
  Result:= False;
  if not FileExists(GetFavoritesFolder+IconFileName) then
     Exit;
  Icon32:= TExIcon.Create;
  Icon32.LoadFromFile(GetFavoritesFolder+IconFileName);
  case Use32bitsIcons of
    True : ColorDepth:= pf32bit;
    False: ColorDepth:= pf24bit;
  end;
  for icoLoop:=0 to Icon32.ImageCount-1 do
  begin
    if (Icon32.Images[icoLoop].Width = 128) and
       (Icon32.Images[icoLoop].Height = 128) and
       (Icon32.Images[icoLoop].PixelFormat = ColorDepth) then
       begin
         Icon32.CurrentImage:= icoLoop;
         tmpIcon:= TIcon.Create;
         tmpIcon.Handle:= Icon32.Handle;
         ImageHolder.Picture.Icon.Assign(tmpIcon);
         ImageHolder.Picture.Icon.ReleaseHandle;
         FreeAndNil(tmpIcon);
         ImageHolder.Refresh;
         Result:= True;
         Break;
       end;
  end;
  FreeAndNil(Icon32);
end;

function TFormMain.GetStatusMessage(MsgCode: String): String;
var
  tmpString: String;
begin
  tmpString:= 'Saving %s games list to file.';
  if MsgCode = 'ReadIniFile' then
     Result:= 'Reading initialization file.'
  else
  if MsgCode = 'UpdateIniFile' then
     Result:= 'Updating initialization file.'
  else
  // Games Class strings

  if MsgCode = 'Save_MAME' then
     Result:= Format(tmpString, [GetSystemIniSection(1)])
  else
  if MsgCode = 'Save_ZiNc' then
     Result:= Format(tmpString, [GetSystemIniSection(2)])
  else
  if MsgCode = 'Save_Daphne' then
     Result:= Format(tmpString, [GetSystemIniSection(3)])
  else
  if MsgCode = 'Save_AGEMAME' then
     Result:= Format(tmpString, [GetSystemIniSection(4)])
  else
  if MsgCode = 'Save_PinMAME' then
     Result:= Format(tmpString, [GetSystemIniSection(5)])
  else
  if MsgCode = 'Save_HazeMD' then
     Result:= Format(tmpString, [GetSystemIniSection(6)])
  else
  if MsgCode = '' then
     Result:= '';
end;

procedure TFormMain.MenuExitClick(Sender: TObject);
begin
  Close;
end;

procedure TFormMain.MenuPreferencesClick(Sender: TObject);
begin
  FormPreferences.ShowModal;
end;

procedure TFormMain.MenuEmulatorSetupClick(Sender: TObject);
begin
  if not Assigned(FormEmulatorsSetup) then
     FormEmulatorsSetup:= TFormEmulatorsSetup.Create(nil);
  FormEmulatorsSetup.ShowModal;
  FreeAndNil(FormEmulatorsSetup);
  if GamesTreeView.Tag = 1 then
     FormMain.SetFocus;
  FormPreferences.ShowEmuVersionSystemDescription.OnClick(Self);
  LoadFoldersAllSystems;
end;

procedure TFormMain.FormCreate(Sender: TObject);
var
  FavoriteFile: TextFile;
  INIFile: TMemIniFile;
begin
  FrontendPath:= ShortToLongPath(ExtractFilePath(Application.ExeName));
  TerminateEmuLoader:= not DirectoryExists(FrontendPath+'resources');
  if TerminateEmuLoader then
     begin
       Application.MessageBox('The folder "resources" could not be found!'+#13+
                              'This is a required folder and the frontend will not work without it.'+#13+
                              'Please, make sure to create the folder and all it''s sub-folders as well.',
                              'Critital Error', mb_Ok+mb_IconError);
       Exit;
     end;
  ThousandSeparator:= Char(',');
  DecimalSeparator:= Char('.');
  case Win32Platform of
    0,1: WinQuotesStr:= '"';
      2: WinQuotesStr:= '';
  end;
  Application.HintPause:= 100;
  FormStatus:= TFormStatus.Create(Self);
  if FileExists(FrontendPath+'EmuLoader.ini') then
     begin
       INIFile:= TMemIniFile.Create(FrontendPath+'EmuLoader.ini');
       LogoFileName:= INIFile.ReadString('Preferences', 'SplashLogoFile', 'resources\images\logo\logo.jpg');
       MenuSmallToolBar.Checked:= Boolean(INIFile.ReadInteger('Configuration', 'SmallToolBar', 0));
       FavoriteUser:= INIFile.ReadString('Favorites', 'User', 'Default');
       MenuViewForceQuotesCommandLine.Checked:= Boolean(INIFile.ReadInteger('Preferences', 'ForceQuotesCommandLine', 0));
       MenuViewForceQuotesCommandLine.OnClick(Self);
       FreeAndNil(INIFile);
       if LogoFileName = '' then
          LogoFileName:= 'resources\images\logo\logo.jpg';
       if FavoriteUser = '' then
          FavoriteUser:= 'Default';
       FavoriteUserFile:= GetFavoriteUserFileName(FavoriteUser);
     end;
  FormStatus.LabelFrontendVersion.Caption:= 'v'+GetFileInfo(Application.ExeName, VersionInfo[3]);
  FormStatus.Show;
  FormStatus.LabelStatusType.Caption:= 'Initializing';
  FormStatus.LabelMessage.Caption:= 'Loading primary settings.';
  FormStatus.Refresh;

  VerifyTempDirectory;
  Use32bitsIcons:= IsThemesEnabled;
  ZipForge.Active:= False;
  CloseStatusWindow:= False;
  Auditing:= False;
  CancelCurrentOperation:= False;
  ProcessingAutomaticMAMEInfoDAT:= False;
  Caption:= Caption+' - [v'+GetFileInfo(Application.ExeName, VersionInfo[3])+']';

  if LoadTrayIcons then
     CoolTrayIcon.IconIndex:= 0;

  if not DirectoryExists(FrontendPath+'ini_files') then
     ForceDirectories(FrontendPath+'ini_files');
  if not DirectoryExists(FrontendPath+'ini_files\favorites') then
     ForceDirectories(FrontendPath+'ini_files\favorites');
  if not FileExists(FrontendPath+'ini_files\favorites\default.el') then
     begin
       try
         AssignFile(FavoriteFile, FrontendPath+GetFavoritesFolder+'default.el');
         ReWrite(FavoriteFile);
         CloseFile(FavoriteFile);
       except
       end;
     end;

  if not FileExists(FrontendPath+'ini_files\favorites.ini') then
     begin
       try
         AssignFile(FavoriteFile, FrontendPath+'ini_files\favorites.ini');
         ReWrite(FavoriteFile);
         CloseFile(FavoriteFile);
       except
       end;
     end;

  if MenuSmallToolBar.Checked then
     MenuSmallToolBar.OnClick(Self);

  ImageNumber:= 1;
  NoScreenshotLoaded:= False;
  FormStatus.LabelMessage.Caption:= 'Loading main screen icons.';
  FormStatus.LabelMessage.Refresh;
  LoadMainScreenIcons;
  FormStatus.LabelMessage.Caption:= 'Loading status bar icons.';
  FormStatus.LabelMessage.Refresh;
  LoadStatusBarIcons;
  FormStatus.LabelMessage.Caption:= 'Loading columns icons.';
  FormStatus.LabelMessage.Refresh;
  LoadCustomizeColumnsIcons;

  FormStatus.LabelMessage.Caption:= 'Initializing memory variables.';
  FormStatus.LabelMessage.Refresh;
  SelectedFilterName:= 'allgames';
  InitializeEmulatorVariables;
  InitializeColumnsSort;
end;

function TFormMain.VerifyTempDirectory: Boolean;
begin
  Result:= DirectoryExists(FrontendPath+'temp');
  if not Result then
     begin
       Result:= ForceDirectories(FrontendPath+'temp');
       if not Result then
          GenerateMessage('Error', 'The folder "'+FrontendPath+'temp" could not be created!'+#13#10+
                          'Please, create a "temp" folder inside frontend''s main folder before going any further.', 2);
     end;
end;

procedure TFormMain.RunMAMEInitialize(SystemID: ShortInt);
begin
  if not FormPreferences.RunEmulatorStartup.Enabled then
     Exit;
  if FileExists(EmulatorFile[SystemID]) and (EmulatorRunOnce) then
     begin
       if FormStatus.Visible then
          begin
            FormStatus.LabelMessage.Caption:= 'Running '+GetSystemIniSection(SystemID)+
                                              ' failsafe.';
            FormStatus.LabelMessage.Refresh;
          end;
       // Win9x only   
       RunProcess('command.com /c '+WinQuotesStr+FormMain.EmulatorFile[SystemID]+WinQuotesStr+' -help', True, Get_DOSBox_Status(False), False);
     end;
end;

procedure TFormMain.RunCreateGamesSys(const SystemID: Integer);
begin
  case SystemID of
     2: CreateGamesListZiNc; // ZiNc (arcade)
     3: CreateGamesListDaphne; // Daphne
  end;
end;

procedure TFormMain.SetColumnsProfileFirstRun;
var
  Loop: Integer;
begin
  for Loop:=0 to MaxArcadeSystems do
      ColumnsProfile[Loop]:= 'default.ini';
  ReadColumnProfile;
end;

procedure TFormMain.FormShow(Sender: TObject);
var
  GamesListFound: packed array[1..MaxArcadeSystems] of Boolean;
  Loop: Integer;
  NewCheckSum, ErrorStr: String;

  function CreateListOKMsg(SystemID: Integer): Boolean;
  begin
    Result:= GenerateMessage('Information', GetEmuFullDescription(SystemID)+#13#10+
                             'Games list file not found. Would you like to create one ?', 1) = mrYes;
  end;

  function CheckNoCreateList(NewBinary: Boolean = False): Boolean;
  begin
    case NewBinary of
      True : Result:= FormPreferences.StartupNewBinaryFound.ItemIndex = 2;
      False: Result:= FormPreferences.StartupGamesListNotFound.ItemIndex = 2;
    end;
  end;

  function CallCreateGamesList(SystemID: Integer; Confirmation: Boolean = False): Boolean;
  begin
    // for MAME based only!!!
    case (EmulatorFile[SystemID] <> '') and
         (FileExists(EmulatorFile[SystemID])) of
      True : SetCurrentDir(ExtractFilePath(EmulatorFile[SystemID]));
      False: Exit;
    end;

    case Confirmation of
      True:
        begin
          GamesListFound[SystemID]:= not CreateListOKMsg(SystemID);
          if not GamesListFound[SystemID] then
             CreateGamesListXML(SystemID);
        end;
      False:
        begin
          CreateGamesListXML(SystemID);
          GamesListFound[SystemID]:= False;
        end;
    end;
    SetCurrentDir(FrontendPath);
  end;

  function CallCreateGamesList2(SystemID: Integer): Boolean;
  begin
    case FormPreferences.StartupGamesListNotFound.ItemIndex of
      0: GamesListFound[SystemID]:= not CreateListOKMsg(SystemID); // ask
      1: GamesListFound[SystemID]:= False; // auto-create
    end;
    Result:= not GamesListFound[SystemID];
  end;

  function CallCreateGamesNewBinary(const SystemID: Integer): Boolean;
  begin
    Result:= False;
    NewCheckSum:= GetMD5_Value(EmulatorFile[SystemID]);
    Application.ProcessMessages;
    if (NewCheckSum <> '') and (EmulatorChecksum[SystemID] <> NewCheckSum) then
       begin
         EmulatorChecksum[SystemID]:= NewCheckSum;
         if not CheckNoCreateList(True) then
            begin
              case FormPreferences.StartupNewBinaryFound.ItemIndex of
                0:
                 begin
                   Result:= GenerateMessage('New File Found', GetEmuFullDescription(SystemID)+#13#10+'MD5 checksum of "'+
                                            EmulatorFile[SystemID]+'" has changed. Would you like to create a new games list ?', 1) = mrYes;
                 end;
                1: Result:= True;
              end;
            end;
       end;
  end;

  function VerifyArcadeMAME(SystemID: Integer): Boolean;
  begin
    if EmulatorFile[SystemID] <> '' then
       begin
         if ((not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(SystemID))) or
             (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(SystemID)))) then
            begin
              if not CheckNoCreateList then
                 CallCreateGamesList(SystemID, (FormPreferences.StartupGamesListNotFound.ItemIndex = 0))
            end
         else
            begin
              if CallCreateGamesNewBinary(SystemID) then
                 CallCreateGamesList(SystemID, False);
            end;
       end;
  end;

  function VerifyConsoleArcade2(SystemID: Integer): Boolean;
  begin
    if EmulatorFile[SystemID] <> '' then
       begin
         if (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(SystemID))) then
            begin
              if not CheckNoCreateList then
                 begin
                   if CallCreateGamesList2(SystemID) then
                      RunCreateGamesSys(SystemID);
                 end;
            end
         else
            begin
              if CallCreateGamesNewBinary(SystemID) then
                begin
                   GamesListFound[SystemID]:= False;
                   RunCreateGamesSys(SystemID);
                end;
            end;
       end;
  end;

  function FirstRunCreateGames(SystemID: Integer): Boolean;
  begin
    GamesListFound[SystemID]:= not (EmulatorFile[SystemID] <> '') and (FileExists(EmulatorFile[SystemID]));
    if not GamesListFound[SystemID] then
       RunCreateGamesSys(SystemID);
  end;

begin
  if GamesTreeView.Tag = 1 then
     Exit;
     
  if TerminateEmuLoader then
     begin
       Application.Terminate;
       PostMessage(Handle, wm_Close, 0, 0);
       Exit;
     end;
  AbortExecution:= True;
  try
    for Loop:=1 to MaxArcadeSystems do
        GamesListFound[Loop]:= True;
  except
    on EOutOfMemory do GenerateMessage('Out of Memory', 'Not enough memory to initialize new binary detection variables!', 2);
  end;
  FormStatus.LabelMessage.Caption:= 'Loading preferences screen icons.';
  FormStatus.LabelMessage.Refresh;
  LoadPreferencesIcons;

  case FileExists(FrontendPath+'EmuLoader.ini') of
    True:
      begin
        case ReadIniFile(ErrorStr) of
          False:
            begin
              if ErrorStr <> '' then
                 GenerateMessage('File Not Found', ErrorStr, 2);
              MenuEmulatorSetup.OnClick(Self);
              SetColumnsProfileFirstRun;
              UpdateIniFile(True);
              ErrorStr:= '';
              if not ReadIniFile(ErrorStr) then
                 begin
                   TerminateEmuLoader:= True;
                   GenerateMessage('Fatal Error', ErrorStr+#13#10+#13#10+
                                   'File(s) still not found. Application will terminate!', 2);
                   Application.Terminate;
                   PostMessage(Handle, wm_Close, 0, 0);
                   Exit;
                 end;
              RunMAMEInitialize(1);
              RunMAMEInitialize(4);
              RunMAMEInitialize(5);
              RunMAMEInitialize(6);
            end;
          True:
            begin
              FormStatus.LabelMessage.Caption:= 'Validating MAME based .ini files.';
              FormStatus.LabelMessage.Refresh;
              ErrorStr:= '';
              if not CheckAllMAMEIniFiles(ErrorStr) then
                 begin
                   if ErrorStr <> '' then
                      GenerateMessage('Error', ErrorStr, 2);
                   MenuEmulatorSetup.OnClick(Self);
                   if MainMenu.Tag = 1 then
                      begin
                        TerminateEmuLoader:= True;
                        Application.Terminate;
                        PostMessage(Handle, wm_Close, 0, 0);
                        Exit;
                      end;
                 end;
            end;
        end;
        // load EmuLoader.ini options
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(1)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyArcadeMAME(1);
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(2)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyConsoleArcade2(2);
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(3)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyConsoleArcade2(3);
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(4)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyArcadeMAME(4);
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(5)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyArcadeMAME(5);
        FormStatus.LabelMessage.Caption:= 'Scanning '+GetSystemIniSection(6)+' checksum.';
        FormStatus.LabelMessage.Refresh;
        VerifyArcadeMAME(6);
      end;
    False:
      begin
        FormStatus.LabelMessage.Caption:= 'Validating games lists.';
        FormStatus.LabelMessage.Refresh;
        if ((not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(1))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(1))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(2))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(3))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(4))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(4))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(5))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(5))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemFileName(6))) and
            (not ValidateFile(FrontendPath+GetMachineTypeGamesFolder+GetSystemROMFileName(6)))
           ) then
           begin
             // there is no "EmuLoader.ini" and no .el files - 1st time execution
             if GenerateMessage('Emu Loader Setup', 'Greetings user. You need to select at least one emulator and '+
                                'create a games list to access the frontend. The following emulators are '+
                                'supported: "MAME (TM) / ZiNc / Daphne / AGEMAME / PinMAME / HazeMD".'+#13#10+
                                'Have fun! :)'+#13#10+'Would you like to view the quick setup guide ?', 1) = mrYes then
                               begin
                                 case FileExists(FrontendPath+'docs\el-quick-setup-quide.txt') of
                                   True : ShellExecute(Handle, 'open', PChar(FrontendPath+'docs\el-quick-setup-quide.txt'), nil, nil, SW_SHOWNORMAL);
                                   False: GenerateMessage('File Not Found', 'Could not load file "'+
                                                    FrontendPath+'docs\el-quick-setup-quide.txt', 2);
                                 end;
                               end;
             AbortExecution:= True;
             FormMain.Width:= 750;
             FormMain.Height:= 570;
             FormMain.Top:= (Screen.Height-550) div 2;
             FormMain.Left:= (Screen.Width-750) div 2;
             MenuEmulatorSetup.OnClick(Self);
             FormStatus.Show;
             case MainMenu.Tag of
               0:
                 begin
                   CallCreateGamesList(1); // MAME
                   FirstRunCreateGames(2); // ZiNc
                   FirstRunCreateGames(3); // Daphne
                   CallCreateGamesList(4); // AGEMAME
                   CallCreateGamesList(5); // PinMAME
                   CallCreateGamesList(6); // HazeMD
                 end;
               1:
                 begin
                   TerminateEmuLoader:= True;
                   Application.Terminate;
                   PostMessage(Handle, wm_Close, 0, 0);
                   Exit;
                 end;
             end;
           end
        else
           begin
             // there is no "EmuLoader.ini" but all .el files exists - just create the ini file
             GenerateMessage('File Missing', Format('%sEmuLoader.ini" not found. Please, configure the frontend!', [FrontendPath]), 2);
             AbortExecution:= True;
             MenuEmulatorSetup.OnClick(Self);
             // need to load folders for all systems!!!!!!!
             case MainMenu.Tag of
               0: LoadFoldersAllSystems;
               1:
                 begin
                   TerminateEmuLoader:= True;
                   Application.Terminate;
                   PostMessage(Handle, wm_Close, 0, 0);
                   Exit;
                 end;
             end;
           end;
        FormStatus.LabelStatusType.Caption:= 'Finalizing Setup';
        FormStatus.LabelMessage.Refresh;
        SetColumnsProfileFirstRun;
        UpdateIniFile(False);
        ReadIniFile(ErrorStr);
        if not FormStatus.Visible then
           FormStatus.Show;
        FormStatus.SetFocus;
      end;
  end;
  FormStatus.LabelStatusType.Caption:= 'Finalizing Setup';
  FormStatus.LabelMessage.Refresh;
  RunMAMEInitialize(1);
  RunMAMEInitialize(4);
  RunMAMEInitialize(5);
  RunMAMEInitialize(6);
  EmulatorRunOnce:= False;
  Screen.Cursor:= crHourGlass;

  FormStatus.LabelMessage.Caption:= 'Loading games icons.';
  FormStatus.LabelMessage.Refresh;
  if CheckDefaultIconsFile then
     ReadDefaultIconsFile;

  if MenuParentalLock.Tag = 1 then
     begin
       FormStatus.LabelMessage.Caption:= 'Activating parental lock.';
       FormStatus.LabelMessage.Refresh;
       MenuParentalLock.Tag:= 0;
       MenuParentalLock.Checked:= True;
       SetLockedGamesList(True);
     end;

  if not GamesListFound[1] then
     PopupRefreshMissingGamesMAME.Click;
  if not GamesListFound[2] then
     PopupRefreshMissingGamesZiNc.Click;
  if not GamesListFound[3] then
     PopupRefreshMissingGamesDaphne.Click;
  if not GamesListFound[4] then
     PopupRefreshMissingGamesAGEMAME.Click;
  if not GamesListFound[5] then
     PopupRefreshMissingGamesPinMAME.Click;
  if not GamesListFound[6] then
     PopupScanMissingGamesHazeMD.Click;

  for Loop:= 1 to MaxArcadeSystems do
      Finalize(GamesListFound[MaxArcadeSystems]);

  SetGameType(SelectedFilterName, True);
  Screen.Cursor:= crHourGlass;
  if PopupGamesUseMAMu_Icons.Tag = 1 then
     PopupGamesUseMAMu_Icons.Click;
  CloseStatusWindow:= True;
  Screen.Cursor:= crDefault;
  if PopupAutomaticGameInformation.Tag = 1 then
     begin
       FormStatus.LabelMessage.Caption:= 'Initializing automatic game information.';
       FormStatus.LabelMessage.Refresh;
       PopupAutomaticGameInformation.Tag:= 0;
       PopupAutomaticGameInformation.Click;
     end;

  LoadListCPU(FilterCPUList);
  if MenuShowImages.Tag = 0 then
     MenuShowImages.Click;

  if MenuViewFullScreen.Tag = 1 then
     MenuViewFullScreen.Click;
end;

function TFormMain.FindNodeGame(GameDescription: String): PVirtualNode;
var
  Data: pGameInfo;
  tempNode: PVirtualNode;
begin
  Result:= nil;
  tempNode:= GamesTreeView.GetFirstVisible;
  if (GameDescription = '') or (not CheckTotal(GamesTreeView)) or (tempNode = nil) then
     Exit;
  Result:= tempNode;
  repeat
    Data:= GamesTreeView.GetNodeData(tempNode);
    if Data.eDescription <> GameDescription then
       tempNode:= GamesTreeView.GetNextVisible(tempNode)
    else
       Result:= tempNode;
  until (not Assigned(tempNode)) or (Data.eDescription = GameDescription);
end;

function TFormMain.FindNodeGameName(GameName: String; SystemID: ShortInt): PVirtualNode;
var
  Data: pGameInfo;
  tempNode: PVirtualNode;
begin
  Result:= nil;
  tempNode:= GamesTreeView.GetFirstVisible;
  if (GameName = '') or (not CheckTotal(GamesTreeView)) or (tempNode = nil) then
     Exit;
  while (Result = nil) and (Assigned(tempNode)) do
  begin
    if Assigned(tempNode) then
       begin
         Data:= GamesTreeView.GetNodeData(tempNode);
         GetSystemID(Data.eROMIdentification);
         if (Data.eName = GameName) then
            begin
              if (SystemID = -1) or (SystemID_Number = SystemID) then
                 Result:= tempNode;
            end;
         tempNode:= GamesTreeView.GetNextVisible(tempNode);
       end;
  end;
  if Result = nil then
     Result:= GamesTreeView.GetFirstVisible;
end;

procedure TFormMain.SelectNode(ItemIndex: Integer);
var
  Node: PVirtualNode;
begin
  if not CheckTotal(GamesTreeView) then
     Exit;
  if (ItemIndex > GamesTreeView.TotalCount) or (ItemIndex = -1) then
     ItemIndex:= 0;
  Node:= GamesTreeView.GetFirst;
  repeat
    if Node.Index <> ItemIndex then
       Node:= GamesTreeView.GetNext(Node);
  until (not Assigned(Node)) or (Node.Index = ItemIndex);
  if Node <> nil then
     begin
       GamesTreeView.Selected[Node]:= True;
       GamesTreeView.FocusedNode:= Node;
       GamesTreeView.ScrollIntoView(Node, True);
     end;
end;

procedure TFormMain.ApplyFilters(FilterName: String; SelectItem: Boolean);
var
  KeepGame: Boolean;
  NodeIndex: PVirtualNode;
  Data: pGameInfo;

  function ReselectItem: Boolean;
  begin
    NoScreenshotLoaded:= False;
    if PopupGamesUseMAMu_Icons.Tag = 0 then
       begin
         if PopupShowParentIconOnly.Checked then
            PopupShowParentIconOnly.OnClick(Self);
       end;
    GamesTreeView.ClearSelection;

    if SelectItem then
       begin
         GetSystemID(SelectedGameID[ButtonGameFilterArcade.Tag]);
         SelectedNode:= FindNodeGameName(SelectedGameName[ButtonGameFilterArcade.Tag], SystemID_Number);
       end;
    if SelectedNode = nil then
       SelectedNode:= GamesTreeView.GetFirstVisible;
    GamesTreeView.Selected[SelectedNode]:= True;
    GamesTreeView.FocusedNode:= SelectedNode;
    SortColumn(False);
  end;

  procedure VerifyFilterOptions;
  var
    favSection: String;
  begin
    if ButtonViewMode.Tag in [2, 3] then
       begin
         if IsSystemEntry(mDriverName) then
            begin
              KeepGame:= True;
              Exit;
            end;
       end;
    KeepGame:= ScanMainFilter(mROMIdentification); // main filter

    {if mROMIdentification in [00..05, 14..29] then
       begin
         // for MAME based
         if KeepGame and MenuViewCPUFilterBox.Checked then
            begin
              if FilterCPU.Text <> '' then
                 KeepGame:= CompareText(Data.eChipCPU, FilterCPU.Text) = 0
              else
                 begin
                   if FilterCPUList.ItemIndex > 0 then
                      KeepGame:= CompareText(Data.eChipCPU, FilterCPUList.Text) = 0
                 end;
            end;
       end;}

    if KeepGame and (ButtonGameFilterNumberScreens.Tag <> 0) then
       begin
         if mNumberScreens >= 1 then
            KeepGame:= mNumberScreens = ButtonGameFilterNumberScreens.Tag
         else
            KeepGame:= False;
       end;

    if KeepGame and MenuParentalLock.Checked then
       KeepGame:= not CheckParentalLock(mROMIdentification, mName); // do not keep if found in parental lock (if enabled)

    if ((ButtonGameFilterWorkingNonWorking.Tag <> 0) or
        (ButtonGameFilterHideBios.Down) or
        (SelectedFilterName <> 'favorites')) and
       KeepGame then
       KeepGame:= not FilterGamesList(SelectedFilterName);

    if (SelectedFilterName = 'favorites') and KeepGame then
       begin
         favSection:= GetSystemFolderName(mROMIdentification);
         case Assigned(FavList) of
           True: KeepGame:= (FavList.IndexOf(mName+'='+favSection) <> -1);
           False: KeepGame:= False;
         end;
       end;
  end;

begin
  if not CheckTotal(GamesTreeView) then
     Exit;
  if FormStatus.Visible then
     begin
       FormStatus.LabelMessage.Caption:= 'Applying filters.';
       FormStatus.Refresh;
     end;
  GamesTreeView.BeginUpdate;
  NodeIndex:= GamesTreeView.GetFirst;
  repeat
    Data:= GamesTreeView.GetNodeData(NodeIndex);
    mROMIdentification:= Data.eROMIdentification;
    GetSystemID(mROMIdentification);
    mName:= Data.eName;
    mClone:= Data.eClone;
    mScreenType1:= Data.eScreenType1;
    mScreenType2:= Data.eScreenType2;
    mScreenType3:= Data.eScreenType3;
    mScreenType4:= Data.eScreenType4;
    mDriverStatus:= Data.eDriverStatus;
    mNumberScreens:= Data.eNumberScreens;
    mCategory:= Data.eCategory;
    mDriverName:= Data.eDriverName;
    mBiosName:= Data.eBiosName;
    mMediaType:= Data.eMediaType;
    VerifyFilterOptions;
    GamesTreeView.IsVisible[NodeIndex]:= KeepGame;
    NodeIndex:= GamesTreeView.GetNext(NodeIndex);
  until NodeIndex = nil;

  {if ButtonViewMode.Tag in [2, 3] then
     begin
       NodeIndex:= GamesTreeView.GetFirst;
       repeat
         Data:= GamesTreeView.GetNodeData(NodeIndex);
         if IsSystemEntry(Data.eDriverName) then
            GamesTreeView.IsVisible[NodeIndex]:= GamesTreeView.GetFirstVisibleChild(NodeIndex) <> nil;
         NodeIndex:= GamesTreeView.GetNext(NodeIndex);
       until NodeIndex = nil;
     end;}
  GamesTreeView.EndUpdate;
  ReselectItem;
end;

procedure TFormMain.SetGameType(FilterName: String; LoadFiles: Boolean);
var
  tempString: String;
  //sClock: Integer;

  function ResetFavoriteSettings: Boolean;
  begin
    if FilterName <> 'favorites' then
       FreeAndNil(FavList)
    else
       LoadGames(-1, True, FavoriteUserFile);

    // here goes the commands to show/hide menu and popup items
    MenuFavoriteProfileEditor.Enabled:= FilterName <> 'favorites';

    PopupRefreshGames.Enabled:= ButtonGameFilterHaveMiss.Enabled;
  end;

  procedure SetNoGamesAvailable;
  begin
    DisplayImage(-1, 'NoGamesAvailable', '', Images, -1, True, 1);
  end;

begin
  //sClock:= GetTickCount;
  if FormStatus.Visible then
     begin
       FormStatus.LabelStatusType.Caption:= 'Loading Games';
       FormStatus.LabelMessage.Caption:= 'Loading games list to memory.';
       FormStatus.Refresh;
     end;
  Screen.Cursor:= crHourGlass;

  case LoadFiles of
    True:
      begin
        CompleteGamesList:= THashedStringList.Create;
        CompleteGamesList.BeginUpdate;
        LoadGames(1, False); // MAME
        LoadGames(2, False); // ZiNc
        LoadGames(3, False); // Daphne
        LoadGames(4, False); // AGEMAME
        LoadGames(5, False); // PinMAME
        LoadGames(6, False); // HazeMD

        LoadGames(500, False); // Custom Games
        CompleteGamesList.EndUpdate;
        if FilterName = 'favorites' then
           ResetFavoriteSettings;

        NoScreenshotLoaded:= False;
        ClearTreeView(GamesTreeView);
        if not AddGames(FilterName, LoadFiles) then
           SetNoGamesAvailable;
        FreeAndNil(CompleteGamesList);
      end;
    False:
      begin
        ResetFavoriteSettings;
        ApplyFilters(FilterName, True);
      end;
  end;

  if not CheckTotalVisible(GamesTreeView) then
     SetNoGamesAvailable;

  UpdateTotalEntriesLabel;

  tempString:= GetZipFolderFull(32);
  SetIcon(IL_ArcadeFilter_Large, IL_ToolBarButtons, ButtonGameFilterArcade.Tag, 1);
  SetToolBarIcon(SelectedFilterName, tempString+'arcade_filters\', IL_ToolBarButtons, 2);

  SetIcon(IL_FilterMasterClone_Large, IL_ToolBarButtons, ButtonGameFilterMasterClone.Tag, 3);
  SetIcon(IL_FilterHaveMiss_Large, IL_ToolBarButtons, ButtonGameFilterHaveMiss.Tag, 4);
  SetIcon(IL_FilterWorkingNonWorking_Large, IL_ToolBarButtons, ButtonGameFilterWorkingNonWorking.Tag, 5);
  SetIcon(IL_FilterNumberScreens_Large, IL_ToolBarButtons, ButtonGameFilterNumberScreens.Tag, 7);

  if CloseStatusWindow then
     FocusGamesList;
  Screen.Cursor:= crDefault;
  //ShowMessage(IntToStr(GetTickCount-sClock));
end;

function TFormMain.ButtonViewImage(ButtonCode: ShortInt): Boolean;
var
  LoopImage: ShortInt;
begin
  Result:= CheckTotal(GamesTreeView);
  if not Result then
     Exit;

  Result:= MenuShowImages.Checked;
  if Result then
     begin
       Screen.Cursor:= crHourGlass;
       if not GetGameData(SelectedNode) then
          begin
            Result:= False;
            Exit;
          end;
       case ButtonCode of
         1: // Next Button
           begin
             Inc(ImageNumber);
             if ImageNumber > 10 then
                begin
                  if FormPreferences.CycleImageTypes.Checked then
                     CycleImageType
                  else
                     begin
                       ButtonPreviousImage.Tag:= -1;
                       ImageNumber:= Images.Tag;
                     end;
                end
             else
                begin
                  for LoopImage:=ImageNumber to 10 do
                  begin
                    if DisplayImage(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone, Images, ImageType, False, 1) then
                       begin
                         ButtonNextImage.Tag:= ButtonNextImage.Tag+1;
                         ImageNumber:= LoopImage;
                         Break;
                       end;
                    Inc(ImageNumber);
                  end;
                  if ImageNumber > 10 then
                     begin
                       if FormPreferences.CycleImageTypes.Checked then
                          CycleImageType
                       else
                          begin
                            ButtonPreviousImage.Tag:= -1;
                            ImageNumber:= Images.Tag;
                          end;
                     end;
                end;
           end;
         0: // Previous Button
           begin
             Dec(ImageNumber);
             if ImageNumber < 1 then
                begin
                  if FormPreferences.CycleImageTypes.Checked then
                     InvertCycleImageType
                  else
                     ImageNumber:= Images.Tag;
                end
             else
                begin
                  for LoopImage:=ImageNumber downto 0 do
                  begin
                    if DisplayImage(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone, Images, ImageType, False, 1) then
                       begin
                         ButtonNextImage.Tag:= ButtonNextImage.Tag-1;
                         ImageNumber:= LoopImage;
                         Break;
                       end;
                    Dec(ImageNumber);
                  end;
                  if ImageNumber < 1 then
                     begin
                       if FormPreferences.CycleImageTypes.Checked then
                          InvertCycleImageType
                       else
                          ImageNumber:= 1;
                     end;
                end;
           end;
       end;
       UpdateLabelImages;
       Screen.Cursor:= crDefault;
     end;
end;

procedure TFormMain.MenuAboutClick(Sender: TObject);
begin
  if not Assigned(FormAbout) then
     FormAbout:= TFormAbout.Create(nil);
  FormAbout.LabelFrontendVersion.Caption:= 'v'+GetFileInfo(Application.ExeName, VersionInfo[3]);
  FormAbout.ShowModal;
  FreeAndNil(FormAbout);
end;

procedure TFormMain.FormActivate(Sender: TObject);
begin
  if TerminateEmuLoader then
     Exit;

  if GamesTreeView.Tag <> 0 then
     Exit;

  GamesTreeView.Tag:= 1;
  SetIcon(IL_ViewMode_Large, IL_ToolBarButtons, ButtonViewMode.Tag, 0);
  GetGameData(SelectedNode);
  if FormPreferences.PlayAudio.Tag = 1 then
     begin
       FormPreferences.PlayAudio.Tag:= 0;
       FormPreferences.PlayAudio.Checked:= True;
       PopulateDevices; // Get all sound devices present on the system
       if FormPreferences.OutputDevice.Items.Count > 0 then
          FormPreferences.OutputDevice.ItemIndex:= FormPreferences.OutputDevice.Tag;

       if CheckSelected(GamesTreeView) and (GameInfoData <> nil) then
          begin
            LoadSound(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone);
          end;
     end;
  Application.ProcessMessages;

  if MenuImageResampler.Tag <> 8 then
     begin
       if MenuImageResampler.Tag <> 0 then
          MenuImageResampler.Items[MenuImageResampler.Tag-1].Click
       else
          MenuImageFilterOff.Click;
     end;

  if ButtonShowMAWSGameInfo.Tag = 1 then
     ButtonShowMAWSGameInfo.Click;

  if FormMain.Tag = 1 then
     WindowState:= wsMaximized
  else
     begin
       if ((FormMain.Top = 0) and (FormMain.Left = 0)) then
          begin
            FormMain.Top:= (Screen.Height-FormMain.Height) div 2;
            FormMain.Left:= (Screen.Width-FormMain.Width) div 2;
          end;
     end;
  FormStatus.Close;
  FormMain.SetFocus;
  FocusGamesList;
  if GamesTreeView.SelectedCount = 0 then
     begin
       SelectedNode:= GamesTreeView.GetFirstVisible;
       if SelectedNode <> nil then
          SelectNode(SelectedNode.Index);
     end;
  UpdateStatusBarGame;
end;

procedure TFormMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var
  Loop: ShortInt;
begin
  // Check "EmuLoader.ini" file not "Read Only" attribute
  // free any created entries
  FreeAndNil(FDrawBuffer); // free this!
  FreeAndNil(FavList);

  if TerminateEmuLoader then
     Exit;

  UpdateINIFile(False);

  if FormPreferences.PlayAudio.Checked then
     InitDeInitFMOD(False, True, False);

  if PopupAutomaticGameInformation.Checked then
     PopupAutomaticGameInformation.Click;

  if PopupGamesUseMAMu_Icons.Checked then
     begin
       if ZipForgeMAMu_.Active then
          ZipForgeMAMu_.CloseArchive;
       FreeAndNil(MAMu_ZipContents);
       FreeAndNil(icoStream);
     end;
  ClearTreeView(GamesTreeView);
  FreeMemoryZipContents;
  if Assigned(ListROMsName) then
     FreeAndNil(ListROMsName);
  if Assigned(ListROMsNameFullPath) then
     FreeAndNil(ListROMsNameFullPath);

  // free memory allocated variables to avoid memory leak
  SetLockedGamesList(False);
  FreeAndNil(FavList);
  for Loop:=1 to MaxArcadeSystems do
  begin
    FreeAndNil(emuROMsFolders[Loop]);
    Finalize(SaveStateDir);
    Finalize(InputDir);
  end;
  for Loop:=0 to MaxArcadeSystems do
      Finalize(ColumnsSort);
end;

function TFormMain.GetGameInfo(GameName: String; el_List: THashedStringList): Integer;
begin
  // Get index line of game for single refresh game
  Result:= el_List.IndexOfName(GameName);
  if Result <> -1 then
     GetROMFields(el_List, Result);
end;

function TFormMain.StopRefreshAllGames: Boolean;
begin
  Result:= False;
  if CancelCurrentOperation then
     begin
       case GenerateMessage('Cancel', 'Stop refreshing the games list ? The current games list will not be changed.', 1) of
         mrYes:
           begin
             Result:= True;
             FreeAndNil(FullList);
             FreeAndNil(ListROMs);

             CancelCurrentOperation:= False;
             FormStatus.KeyPreview:= False;
             FormStatus.ProgressBar.Progress:= 0;
             FormStatus.ProgressBar.Tag:= 0;
             FormStatus.Close;
             SetCurrentDir(FrontendPath);
           end;
         mrNo: CancelCurrentOperation:= False;
       end;
     end;
end;

procedure TFormMain.MenuImagesClick(Sender: TObject);
begin
  PopupShowFirstImage.Enabled:= ImageNumber > 1;
  PopupDeleteCurrentImage.Enabled:= not NoScreenshotLoaded;
  PopupRenameCurrentImage.Enabled:= not NoScreenshotLoaded;
end;

procedure TFormMain.SendEMailEmuLoaderClick(Sender: TObject);
begin
  //ShellExecute(Handle, 'open', 'mailto:emuloader@mameworld.net?subject=Emu Loader Bugs Report...', nil, nil, SW_SHOWNORMAL);
end;

procedure TFormMain.MenuVisitEmuLoaderHomepageClick(Sender: TObject);
begin
  ShellExecute(Handle, 'open', PAnsiChar(TMenuItem(Sender).Hint), nil, nil, SW_SHOWNORMAL);
end;

procedure TFormMain.MenuRestoreMainScreenDefaultScreenSizePositionClick(
  Sender: TObject);
begin
  if FormMain.WindowState = wsNormal then
     begin
       FormMain.Width:= 750;
       FormMain.Height:= 550;
       PanelScreenshotsArea.Width:= 345;
       FormMain.Top:= (Screen.Height shr 1)-(Height shr 1)-1;
       FormMain.Left:= (Screen.Width shr 1)-(Width shr 1)-1;
     end;
end;

procedure TFormMain.MenuAdvancedUserClick(Sender: TObject);
begin
  MenuRestoreMainScreenDefaultScreenSizePosition.Enabled:= (FormMain.WindowState = wsNormal);
end;

procedure TFormMain.CallEmulatorOptions(EmulatorFileName: String; sysID: ShortInt);
var
  iniFile: String;

  procedure ShowErrorMsg;
  begin
    GenerateMessage('Error', GetEmuFullDescription(sysID)+#13#10+'Select a '+
                             'filename for this emulator first.', 2);
  end;

begin
  case sysID of
    1, 4, 5, 6:
      begin
        if EmulatorFileName <> '' then
           begin
             iniFile:= GetMAMEIniFileName(EmulatorFileName, sysID);

             if not Assigned(FormMAMESettings) then
                FormMAMESettings:= TFormMAMESettings.Create(nil);
             LoadMAMESettingsIcons(FormMAMESettings.IL_MAMESettings);
             FormMAMESettings.Tag:= 0; // means default options
             FormMAMESettings.EmulatorString:= EmulatorFileName;
             FormMAMESettings.emuIni:= iniFile;
             FormMAMESettings.sysID:= sysID;
             FormMAMESettings.Caption:= Format('%s Settings', [GetSystemIniSection(sysID)]);
             FormMAMESettings.Caption:= FormMAMESettings.Caption+
                                        Format(' - [%s]', [EmulatorFileName]);
             FormMAMESettings.ReadFileIni.Text:= iniFile;
             FormMAMESettings.ReadFile.Hint:= Format('Read "%s"', [iniFile]);

             if EmulatorVersion[sysID] <> '' then
                FormMAMESettings.LabelEmuVersionInfo.Caption:=
                                         Format(FormMAMESettings.LabelEmuVersionInfo.Hint,
                                                [EmulatorVersion[sysID]])
             else
                begin
                  if Assigned(FormEmulatorsSetup) then
                     FormMAMESettings.LabelEmuVersionInfo.Caption:=
                                              Format(FormMAMESettings.LabelEmuVersionInfo.Hint,
                                                [EmulatorVersion[sysID]])
                end;
             FormMAMESettings.ShowModal;
             FreeAndNil(FormMAMESettings);
             SetCurrentDir(FrontendPath);
             LoadFolders_MAME(sysID);
           end
        else
           ShowErrorMsg;
      end;
    2:
      begin
        if EmulatorFileName <> '' then
           begin
             SetCurrentDir(ExtractFilePath(EmulatorFileName));
             if not Assigned(FormZiNcSettings) then
                FormZiNcSettings:= TFormZiNcSettings.Create(nil);

             FormZiNcSettings.Tag:= 0; // means default options
             FormZiNcSettings.zGameName:= 'zinc_el';
             FormZiNcSettings.ReadZiNcCFG.Hint:= Format('Read "%s.cfg"', [GetFolderZiNc_cfg+FormZiNcSettings.zGameName]);
             FormZiNcSettings.ShowModal;
             FreeAndNil(FormZiNcSettings);
             SetCurrentDir(FrontendPath);
             LoadFoldersConsole(2);
           end
        else
           ShowErrorMsg;
      end;
  end;
end;

procedure TFormMain.MenuMAMEDefaultSettingsClick(Sender: TObject);
begin
  CallEmulatorOptions(EmulatorFile[TMenuItem(Sender).ImageIndex], TMenuItem(Sender).ImageIndex);
end;

procedure TFormMain.MenuColumnsEditorClick(Sender: TObject);
begin
  if not Assigned(FormColumnsEditor) then
     FormColumnsEditor:= TFormColumnsEditor.Create(nil);
  LoadCustomizeColumnsIcons;
  FormColumnsEditor.ShowModal;
  FreeAndNil(FormColumnsEditor);
end;

procedure TFormMain.CallDeleteFile(FileName, Folder: String);

  procedure GetFolder;
  var
    BinaryFile, TextLine: String;
    MAMEIniFile: THashedStringList;
    Loop: Integer;
    FoundFolder: Boolean;
  begin
    BinaryFile:= EmulatorFile[SystemID_Number];
    MAMEIniFile:= THashedStringList.Create;
    MAMEIniFile.LoadFromFile(GetMAMEIniFileName(BinaryFile, SystemID_Number));
    FoundFolder:= False;
    for Loop:=0 to MAMEIniFile.Count -1 do
    begin
     TextLine:= MAMEIniFile[Loop];
      if Folder = 'cfg' then
          begin
          if Copy(TextLine, 1, 14) = 'cfg_directory ' then
              FoundFolder:= True;
         end
      else
      if Folder = 'nvram' then
          begin
          if Copy(TextLine, 1, 16) = 'nvram_directory ' then
              FoundFolder:= True;
         end
      else
      if Folder = 'memcard' then
         begin
           if Copy(TextLine, 1, 18) = 'memcard_directory ' then
              FoundFolder:= True;
         end
      else
      if Folder = 'input' then
         begin
           if Copy(TextLine, 1, 16) = 'input_directory ' then
              FoundFolder:= True;
         end
      else
      if Folder = 'state' then
         begin
           if Copy(TextLine, 1, 16) = 'state_directory ' then
              FoundFolder:= True;
         end;

      if FoundFolder then
         begin
           Folder:= ExtractMAMEIniValue(TextLine);
           Break;
         end;
    end;
    FreeAndNil(MAMEIniFile);
  end;

begin
  if not CheckSelected(GamesTreeView) then
     Exit;

  GetFolder;
  if Folder = '' then
     begin
       GenerateMessage('Error', 'Folder is empty, cannot continue.', 2);
       Exit;
     end;
  Folder:= FullEmuFolderFix(Folder, SystemID_Number);
  case FileExists(Folder+'\'+FileName) of
    True:
      begin
        if GenerateMessage('Delete File', Format('Delete file "%s". Are you sure ?', [Folder+'\'+FileName]), 1, True) = mrYes then
           DeleteFile(Folder+'\'+FileName);
        Application.ProcessMessages;
      end;
    False: GenerateMessage('File Not Found', 'There is nothing to delete!', 2);
  end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.MenuParentalLockClick(Sender: TObject);

  procedure DeactivateParentalLock;
  begin
    GenerateMessage('No Games Found', 'There are no games on the parental lock list! '+
                    'You must select at least one game for this to work.', 2);
    MenuParentalLock.Checked:= False;
  end;

begin
  Screen.Cursor:= crHourGlass;
  case MenuParentalLock.Checked of
    True:
      begin
        case FileExists(FrontendPath+'ini_files\parental_lock.ini') of
          False:
            begin
              // start new session
              if not Assigned(FormParentalLockEditor) then
                 FormParentalLockEditor:= TFormParentalLockEditor.Create(nil);
              GenerateMessage('Welcome To Parental Lock Mode', 'Please, add keywords to the keywords list '+
                              'and choose the games to protect.', 2);
              FormParentalLockEditor.HaveProtectedGames:= False;
              FormParentalLockEditor.ShowModal;
              FreeAndNil(FormParentalLockEditor);
              case SetLockedGamesList(True) of
                True: SetGameType(SelectedFilterName, False);
                False:
                  begin
                    SetLockedGamesList(False);
                    DeactivateParentalLock;
                  end;
              end;
            end;
          True:
            begin
              // need to open the file and uncrypt first line
              // password=4343248249823498
              if GetFileSize(FrontendPath+'ini_files\parental_lock.ini') > 0 then
                 begin
                   //ParentalLockPasswordString:= LoadParentalLockPassword;
                   case SetLockedGamesList(True) of
                     True: SetGameType(SelectedFilterName, False);
                     False:
                       begin
                         SetLockedGamesList(False);
                         DeactivateParentalLock;
                       end;
                   end;
                 end
              else
                 DeactivateParentalLock;
            end;
        end;
      end;
    False:
      begin
        // call the password screen to deactivate the lock
        // if password accepted, then the games are unlocked
        if not Assigned(FormParentalLockPasswordLogout) then
           FormParentalLockPasswordLogout:= TFormParentalLockPasswordLogout.Create(nil);
        FormParentalLockPasswordLogout.Password.Tag:= 0;
        FormParentalLockPasswordLogout.ShowModal;
        FreeAndNil(FormParentalLockPasswordLogout);
        case MenuParentalLock.Tag of
          0: begin
               SetLockedGamesList(False);
               SetGameType(SelectedFilterName, False);
             end;
          1: begin
               MenuParentalLock.Tag:= 0;
               MenuParentalLock.Checked:= True;
             end;
        end;
      end;
  end;
  if CloseStatusWindow then
     FormStatus.Close;
  Screen.Cursor:= crDefault;
end;

procedure TFormMain.MenuPlayRecordedGameClick(Sender: TObject);
begin
  MenuRecordGame.Checked:= False;
end;

procedure TFormMain.MenuRecordGameClick(Sender: TObject);
begin
  MenuPlayRecordedGame.Checked:= False;
end;

procedure TFormMain.MenuFavoriteProfileEditorClick(Sender: TObject);
begin
  if not Assigned(FormFavoriteGamesProfileEditor) then
     FormFavoriteGamesProfileEditor:= TFormFavoriteGamesProfileEditor.Create(nil);
  FormFavoriteGamesProfileEditor.ShowModal;
  FreeAndNil(FormFavoriteGamesProfileEditor);
end;

procedure TFormMain.SetImageMode(TypeIndex: ShortInt);
begin
  ImageNumber:= 1;
  ImageType:= TypeIndex;

  if TypeIndex > Length(ImageTypeArray)-1 then
     GenerateMessage('Error', 'Image type index is higher than supported. '+
                     'Cannot set filename to update the image icon in tool bar buttons.'+#13#10+'Index: '+IntToStr(TypeIndex), 2)
  else
  if ImageTypeArray[TypeIndex, 1] = '' then
     GenerateMessage('Error', 'Could not set filename to update the image '+
                     'icon in tool bar buttons.', 2)
  else
     SetToolBarIcon(ImageTypeArray[TypeIndex, 1], GetZipFolderFull(32), IL_ToolBarButtons, 8);
  //SetIcon(IL_ImagesViewMode_Large, IL_ToolBarButtons, TypeIndex, 7);
  SetIcon(IL_ImagesViewMode_Small, IL_MenuPopup, TypeIndex, 58);
  ButtonImagesViewMode.Tag:= ImageType;
  with FormPreferences do
  begin
    case ImageType of
       0: begin
            TitleSnapshotsBackgroundColor.OnSelect(TitleSnapshotsBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionTitleSnapshots.Text;
          end;
       1: begin
            GameSnapshotsBackgroundColor.OnSelect(GameSnapshotsBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionGameSnapshots.Text;
          end;
       2: begin
            MarqueesBackgroundColor.OnSelect(MarqueesBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionMarquees.Text;
          end;
       3: begin
            FlyersBackgroundColor.OnSelect(FlyersBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionFlyers.Text;
          end;
       4: begin
            CabinetsBackgroundColor.OnSelect(CabinetsBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionCabinets.Text;
          end;
       5: begin
            ControlPanelsBackgroundColor.OnSelect(ControlPanelsBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionControlPanels.Text;
          end;
       6: begin
            ControlPanelLayoutsBackgroundColor.OnSelect(ControlPanelLayoutsBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionControlPanelLayouts.Text;
          end;
       7: begin
            SelectBackgroundColor.OnSelect(SelectBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionSelect.Text;
          end;
       8: begin
            VersusBackgroundColor.OnSelect(VersusBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionVersus.Text;
          end;
       9: begin
            WallpapersBackgroundColor.OnSelect(WallpapersBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionWallpapers.Text;
          end;
      10: begin
            HardwareBackgroundColor.OnSelect(HardwareBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionHardware.Text;
          end;
      11: begin
            CustomImageBackgroundColor.OnSelect(CustomImageBackgroundColor);
            ButtonImageToolBarViewMode.Hint:= FormPreferences.DescriptionCustomImage.Text;
          end;
   end;
   ButtonImagesViewMode.Hint:= 'Images view mode ['+ButtonImageToolBarViewMode.Hint+']';
 end;
  NoScreenshotLoaded:= False;
  FreeMemoryZipContents; // clear all memory zip contents

  if not FormStatus.Visible then
     begin
       Images.Hint:= '';
       MenuShowImages.OnClick(Self);
     end;
end;

procedure TFormMain.MenuParentalLockEditorClick(
  Sender: TObject);
begin
  case MenuParentalLock.Checked of
    False:
      begin
        if not Assigned(FormParentalLockEditor) then
           begin
             FormParentalLockEditor:= TFormParentalLockEditor.Create(nil);
             LoadParentalLockIcons;
           end;

        FormParentalLockEditor.HaveProtectedGames:= ValidateFile(FrontendPath+'ini_files\parental_lock.ini');
        if not FormParentalLockEditor.HaveProtectedGames then
           GenerateMessage('Welcome To Parental Lock Mode', 'Please, add keywords to the keywords list and choose the games to lock.', 2);
        FormParentalLockEditor.ShowModal;
        FreeAndNil(FormParentalLockEditor);
      end;
    True: GenerateMessage('Parental Lock Activated', 'Access to parental lock manager denied! To add/delete games to/from the protected list, the parental lock must be disabled.', 2);
  end;
end;

procedure TFormMain.ResetMAMu_ImageList;
var
  Node: PVirtualNode;
  Data: pGameInfo;
begin
  if GamesTreeView.Tag = 0 then
     Exit;
  ClearImageList(IL_StandardIconsLarge);
  ClearImageList(IL_StandardIconsStandard);
  ClearImageList(IL_StandardIconsSmall);
  if CheckDefaultIconsFile then
     ReadDefaultIconsFile;

  if CheckTotal(GamesTreeView) then
     begin
       GamesTreeView.BeginUpdate;
       Node:= GamesTreeView.GetFirst;
       repeat
         Data:= GamesTreeView.GetNodeData(Node);
         Data.eIconLoaded:= False;
         case IsSystemEntry(Data.eDriverName) of
           True : Data.eImageIndex:= Data.eROMIdentification+MaxGameID;
           False: Data.eImageIndex:= Data.eROMIdentification;
         end;
         Node:= GamesTreeView.GetNext(Node);
       until (not Assigned(Node));
       GamesTreeView.EndUpdate;
     end;
end;

procedure TFormMain.PopupGamesUseMAMu_IconsClick(Sender: TObject);
var
  ZipFile: String;
  ArchiveItem: TZFArchiveItem;

  procedure SetGameIconSize;
  begin
    if GamesTreeView.Tag = 1 then
       begin
         case PopupGameIconSize.Tag of
           0: PopupIconSizeLarge.Click;
           1: PopupIconSizeStandard.Click;
           2: PopupIconSizeSmall.Click;
         end;
       end;
  end;
begin
  Screen.Cursor:= crHourGlass;
  ResetMAMu_ImageList;
  case PopupGamesUseMAMu_Icons.Checked of
    True:
      begin
        case CheckTotal(GamesTreeView) of
          True:
            begin
              ZipFile:= VerifyZipType(FormPreferences.MAMu_Icons.Text, False);
              case FileExists(GetZipFolderFull(30)+ZipFile) of
                True:
                  begin
                    with ZipForgeMAMu_ do
                    begin
                      FileName:= GetZipFolderFull(30)+ZipFile;
                      try
                        OpenArchive(fmOpenRead+fmShareDenyNone);
                        if FileCount > 0 then
                           begin
                             if FindFirst('*.*', ArchiveItem) then
                                begin
                                  MAMu_ZipContents:= THashedStringList.Create;
                                  MAMu_ZipContents.BeginUpdate;
                                  repeat
                                    MAMu_ZipContents.Add(AnsiLowerCase(AnsiLowerCase(ArchiveItem.StoredPath+ArchiveItem.FileName)));
                                  until (not FindNext(ArchiveItem));
                                  MAMu_ZipContents.EndUpdate;
                                end;
                           end;
                        icoStream:= TMemoryStream.Create;
                      except
                        CloseArchive;
                        FreeAndNil(icoStream);
                        FreeAndNil(MAMu_ZipContents);
                      end;
                    end;
                  end;
              end;
              GamesTreeView.BeginUpdate;
              SetGameIconSize;
              GamesTreeView.EndUpdate;
            end;
          False:
            begin
              case PopupGamesUseMAMu_Icons.Tag of
                0: PopupGamesUseMAMu_Icons.Click;
                1: SetGameIconSize;
              end;
            end;
        end;
      end;
    False:
      begin
        PopupGamesUseMAMu_Icons.Checked:= False;
        FreeAndNil(MAMu_ZipContents);
        FreeAndNil(icoStream);
        ZipForgeMAMu_.CloseArchive;
        SetGameIconSize;
      end;
  end;
  if PopupGamesUseMAMu_Icons.Tag = 1 then
     PopupGamesUseMAMu_Icons.Tag:= 0;
  FormStatus.Close;
  Screen.Cursor:= crDefault;
  FocusGamesList;
end;

procedure TFormMain.MenuShowActiveMAMEROMPathsClick(Sender: TObject);
var
  Counter: Integer;
  ROMsString: String;
begin
  SystemID_Number:= TMenuItem(Sender).Tag;
  ROMsString:= '';
  if Assigned(emuROMsFolders[SystemID_Number]) then
     begin
       for Counter:=0 to emuROMsFolders[SystemID_Number].Count-1 do
       begin
         if emuROMsFolders[SystemID_Number].Strings[Counter] <> '' then
            begin
              if ROMsString <> '' then
                 ROMsString:= ROMsString+#13#10;
              ROMsString:= ROMsString+emuROMsFolders[SystemID_Number].Strings[Counter];
            end;
       end;
       GenerateMessage(GetEmuFullDescription(SystemID_Number)+' ROM Paths', ROMsString, 2);
     end;
end;

procedure TFormMain.MenuShowImagesClick(Sender: TObject);
begin
  if (not NotebookImages.PageIndex = 0) and (not ButtonShowMAWSGameInfo.Checked) then
     NotebookImages.PageIndex:= 0;
  ButtonImagesViewMode.Enabled:= MenuShowImages.Checked;
  ButtonImageToolBarViewMode.Enabled:= MenuShowImages.Checked;
  case MenuShowImages.Checked of
    True:
      begin
        if not CheckSelected(GamesTreeView) then
           Exit;
        if not GetGameData(SelectedNode) then
           Exit;
        case PanelGameDocuments.Visible of
          True:
            begin
              if not ButtonShowMAWSGameInfo.Checked then
                 begin
                   SplitterMAMEInfo.Visible:= True;
                   SetLayoutGameDocuments;
                 end;
            end;
          False:
            begin
              case ButtonShowMAWSGameInfo.Checked of
                True: Exit;
                False:
                  begin
                    if not PanelScreenshotsArea.Visible then
                       PanelScreenshotsArea.Visible:= True;
                    if not Splitter.Visible then
                       Splitter.Visible:= True;
                  end;
                end;
            end;
        end;
        if not PanelImage.Visible then
           PanelImage.Visible:= True;
        if not PanelImagesDocuments.Visible then
           PanelImagesDocuments.Visible:= True;

        NoScreenshotLoaded:= False;
        if DisplayImage(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone, Images, ImageType, True, 1) then
           begin
             Images.Bitmap.Changed;
           end;
        UpdateLabelImages;
        ShowZipErrors;
      end;
    False:
      begin
        ClearImage;
        case PanelGameDocuments.Visible of
          True:
            begin
              PanelImage.Visible:= False;
              SplitterMAMEInfo.Visible:= False;
              PanelGameDocuments.Align:= alClient;
              MAMEInfoTextHolder.Refresh;
            end;
          False:
            begin
              case ButtonShowMAWSGameInfo.Checked of
                True:
                  begin
                    if not NotebookImages.PageIndex = 1 then
                       NotebookImages.PageIndex:= 1;
                  end;
                False:
                  begin
                    PanelScreenshotsArea.Visible:= False;
                    Splitter.Visible:= False;
                    if not NotebookImages.PageIndex = 0 then
                       NotebookImages.PageIndex:= 0;
                  end;
              end;
            end;
        end;
        FreeMemoryZipContents;
      end;
  end;
end;

procedure TFormMain.PopupShowHaveMissClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonGameFilterHaveMiss.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       Exit;
     end;
  if TMenuItem(Sender).Checked then
     begin
       ButtonGameFilterHaveMiss.Tag:= TMenuItem(Sender).Tag;
       SetGameType(SelectedFilterName, False);
     end;
end;

procedure TFormMain.ZipForgeProcessFileFailure(Sender: TObject;
  FileName: String; Operation: TZFProcessOperation; NativeError,
  ErrorCode: Integer; ErrorMessage: String; var Action: TZFAction);
begin
  case Operation of
    poExtract:
      GenerateMessage('Error', Format('An error has occurred while extracting from file "%s".'+#13#10+#13#10+'%s', [FileName, ErrorMessage]), 2);
    poDelete:
      GenerateMessage('Error', Format('An error has occurred while deleting from file "%s".'+#13#10+#13#10+'%s', [FileName, ErrorMessage]), 2);
  end;
end;

procedure TFormMain.TimerFMODTimer(Sender: TObject);
begin
  if FSongs[0].Playing then
      begin
        if FSOUND_Stream_GetTime(FSongs[0].Stream) = FSOUND_Stream_GetLengthMs(FSongs[0].Stream) then
           StopSound;
      end;
end;

procedure TFormMain.MenuUserManualClick(Sender: TObject);
begin
  case FileExists(FrontendPath+'emuloader.chm') of
    True : ShellExecute(Handle, 'open', PChar(FrontendPath+'emuloader.chm'), nil, nil, SW_SHOWNORMAL);
    False: GenerateMessage('Error', Format('File "%s" was not found!', [FrontendPath+'emuloader.chm']), 2);
  end;
end;

procedure TFormMain.MenuImageFilterOffClick(Sender: TObject);
const
  ResamplerList: array[0..2] of TBitmap32ResamplerClass =
      (TNearestResampler, TLinearResampler, TDraftResampler);
  KernelResamplerList: array[3..8] of TCustomKernelClass =
      (TBoxKernel, TCosineKernel, TSplineKernel, TCubicKernel,
       TMitchellKernel, TLanczosKernel);
begin
  Images.BeginUpdate;
  MenuImageResampler.Tag:= TMenuItem(Sender).Tag;
  case MenuImageResampler.Tag of
  0..2: ResamplerList[MenuImageResampler.Tag].Create(Images.Bitmap);
  3..8:
    begin
      TKernelResampler.Create(Images.Bitmap);
      TKernelResampler(Images.Bitmap.Resampler).Kernel :=
                    TCustomKernelClass(KernelResamplerList[MenuImageResampler.Tag]).Create;
    end;
  end;
  Images.EndUpdate;
  Images.Repaint;
end;

procedure TFormMain.PopupRefreshAvailableGamesMAMEClick(Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 1);
end;

procedure TFormMain.ButtonGameFilterHideBiosClick(Sender: TObject);
begin
  SetGameType(SelectedFilterName, False);
end;

procedure TFormMain.PopupShowMasterCloneClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonGameFilterMasterClone.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       Exit;
     end;
  if TMenuItem(Sender).Checked then
     begin
       ButtonGameFilterMasterClone.Tag:= TMenuItem(Sender).Tag;
       SetGameType(SelectedFilterName, False);
     end;
end;

procedure TFormMain.PopupShowWorkingNonWorkingClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonGameFilterWorkingNonWorking.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       Exit;
     end;
  if TMenuItem(Sender).Checked then
     begin
       ButtonGameFilterWorkingNonWorking.Tag:= TMenuItem(Sender).Tag;
       SetGameType(SelectedFilterName, False);
     end;
end;

function TFormMain.ValidateFile(FileName: String): Boolean;
begin
  Result:= (FileExists(FileName)) and
           (GetFileSize(FileName) > 0);
end;

procedure TFormMain.PopupShowParentIconOnlyClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: pGameInfo;
begin
  if CheckTotal(GamesTreeView) and PopupGamesUseMAMu_Icons.Checked then
     begin
       Screen.Cursor:= crHourGlass;
       ResetMAMu_ImageList;
       GamesTreeView.BeginUpdate;
       Node:= GamesTreeView.GetFirst;
       repeat
         Data:= GamesTreeView.GetNodeData(Node);
         Data.eIconLoaded:= False;
         case IsSystemEntry(Data.eDriverName) of
           True : Data.eImageIndex:= Data.eROMIdentification+MaxGameID;
           False: Data.eImageIndex:= Data.eROMIdentification;
         end;
         Node:= GamesTreeView.GetNext(Node);
       until not Assigned(Node);
       GamesTreeView.EndUpdate;
       Screen.Cursor:= crDefault;
     end;
end;

function TFormMain.GetColumnText(DataHolder: pGameInfo; idxColumn: Integer): String;
begin
  case idxColumn of
    00: Result:= DataHolder.eDescription;
    01: Result:= DataHolder.eYear;
    02: Result:= DataHolder.eManufacturer;
    03: Result:= aAudioChannels[DataHolder.eAudioChannels];
    04: Result:= aAudioSamples[DataHolder.eAudioSamples];
    05:
      begin
        case DataHolder.eNumberScreens of
          -1, 0: Result:= '';
          1: Result:= IntToStr(DataHolder.eNumberScreens)+' screen';
        else
          Result:= IntToStr(DataHolder.eNumberScreens)+' screens';
        end;
      end;

    06: Result:= aScreenType[DataHolder.eScreenType1];
    07: Result:= MountOrientation(DataHolder.eScreenRotation1);
    08: Result:= MountResolution(DataHolder.eResolutionWidth1, DataHolder.eResolutionHeight1, DataHolder.eScreenRotation1);
    09:
      begin
        Result:= DataHolder.eRefreshRate1;
        if Result <> '' then
           Result:= Result+' Hz';
      end;
    10: Result:= aScreenType[DataHolder.eScreenType2];
    11: Result:= MountOrientation(DataHolder.eScreenRotation2);
    12: Result:= MountResolution(DataHolder.eResolutionWidth2, DataHolder.eResolutionHeight2, DataHolder.eScreenRotation2);
    13:
      begin
        Result:= DataHolder.eRefreshRate2;
          if Result <> '' then
             Result:= Result+' Hz';
      end;

    14: Result:= aScreenType[DataHolder.eScreenType3];
    15: Result:= MountOrientation(DataHolder.eScreenRotation3);
    16: Result:= MountResolution(DataHolder.eResolutionWidth3, DataHolder.eResolutionHeight3, DataHolder.eScreenRotation3);
    17:
      begin
        Result:= DataHolder.eRefreshRate3;
          if Result <> '' then
             Result:= Result+' Hz';
      end;

    18: Result:= aScreenType[DataHolder.eScreenType4];
    19: Result:= MountOrientation(DataHolder.eScreenRotation4);
    20: Result:= MountResolution(DataHolder.eResolutionWidth4, DataHolder.eResolutionHeight4, DataHolder.eScreenRotation4);
    21:
      begin
        Result:= DataHolder.eRefreshRate4;
          if Result <> '' then
             Result:= Result+' Hz';
      end;

    22: Result:= aStatus[DataHolder.eDriverStatus];
    23: Result:= aStatus[DataHolder.eEmulationStatus];
    24: Result:= aStatus[DataHolder.eColorStatus];
    25: Result:= aStatus[DataHolder.eSoundStatus];
    26: Result:= aStatus[DataHolder.eGraphicStatus];
    27: Result:= aStatus[DataHolder.eCocktailStatus];
    28: Result:= aStatus[DataHolder.eProtectionStatus];

    29: Result:= DataHolder.eCategory;
    30: Result:= DataHolder.eVersionAdded;
    31: Result:= DataHolder.eName;
    32:
      begin
        case MenuGamesFillAllCloneEntries.Checked of
          True:
            begin
              if DataHolder.eClone = '' then
                 Result:= DataHolder.eName
              else
                 Result:= DataHolder.eClone;
            end;
          False: Result:= DataHolder.eClone;
        end;
      end;
    33:
      begin
        case IsSystemEntry(DataHolder.eDriverName) of
          True : Result:= '';
          False: Result:= DataHolder.eDriverName;
        end;
      end;
    34:
      begin
        if not (DataHolder.eROMIdentification in [06..13]) then
           Result:= DataHolder.eMerged else Result:=  '';
      end;
    35: Result:= DataHolder.ePlayTime;
    36:
      begin
        if DataHolder.ePlayed = 0 then
           Result:= ''
        else
           Result:= IntToStr(DataHolder.ePlayed)+'x';
      end;
    37: Result:= DataHolder.eNumberPlayers;
    38: Result:= aControlType[DataHolder.eControlType, 0];
    39: Result:= aSaveState[DataHolder.eSaveState];
  end;
end;

procedure TFormMain.GamesTreeViewGetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: WideString);
var
  Data: pGameInfo;
begin
  Data:= Sender.GetNodeData(Node);
  CellText:= GetColumnText(Data, Column);
end;

procedure TFormMain.GamesTreeViewGetHint(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex;
  var LineBreakStyle: TVTTooltipLineBreakStyle; var HintText: WideString);
var
  Data: pGameInfo;
begin
  Data:= Sender.GetNodeData(Node);
  HintText:= GetColumnText(Data, Column);
end;

procedure TFormMain.GamesTreeViewGetImageIndex(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Kind: TVTImageKind; Column: TColumnIndex;
  var Ghosted: Boolean; var ImageIndex: Integer);
var
  Data: pGameInfo;
begin
  if Kind in [ikNormal, ikSelected] then
     begin
       if Column = 0 then
          begin
            Data:= Sender.GetNodeData(Node);
            case PopupGamesUseMAMu_Icons.Checked of
              True:
                begin
                  if not IsSystemEntry(Data.eDriverName) then
                     begin
                       if (not Data.eIconLoaded) then
                          begin
                            case PopupGameIconSize.Tag of
                              0: Data.eImageIndex:= AddMAMu_Icon(Data.eROMIdentification, Data.eName, Data.eClone, IL_StandardIconsLarge);
                              1: Data.eImageIndex:= AddMAMu_Icon(Data.eROMIdentification, Data.eName, Data.eClone, IL_StandardIconsStandard);
                              2: Data.eImageIndex:= AddMAMu_Icon(Data.eROMIdentification, Data.eName, Data.eClone, IL_StandardIconsSmall);
                            end;
                            Data.eIconLoaded:= True;
                            if Data.eImageIndex = -1 then
                               Data.eImageIndex:= Data.eROMIdentification;
                          end;
                     end;
                end;
            end;
            ImageIndex:= Data.eImageIndex;
            if GameIsClone(Data.eClone) then
               Ghosted:= ButtonGroupedBlendCloneIcons50Percent.Checked;
          end;
     end;
end;

procedure TFormMain.GamesTreeViewHeaderClick(Sender: TVTHeader;
  Column: TColumnIndex; Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  case Button of
    mbLeft:
      begin
        with Sender, Treeview do
        begin
          if SortColumn > NoColumn then
             Columns[SortColumn].Options:= Columns[SortColumn].Options + [coParentColor];

          if (SortColumn = NoColumn) or (SortColumn <> Column) then
          begin
            SortColumn:= Column;
            SortDirection:= sdAscending;
          end
          else
            if SortDirection = sdAscending then
              SortDirection:= sdDescending
            else
              SortDirection:= sdAscending;

          if not FormPreferences.GamesBackgroundImageEnable.Checked then
             Columns[SortColumn].Color:= FormPreferences.SortedColumnColor.Selected; // }$F7F7F7;
          ColumnsSort[ButtonGameFilterArcade.Tag, 0]:= SortColumn; // sorted column
          ColumnsSort[ButtonGameFilterArcade.Tag, 1]:= Ord(SortDirection = sdDescending); // sort direction
          SortTree(SortColumn, SortDirection, False);
          ScrollIntoView(SelectedNode, True);
        end;
      end;
    mbRight: MenuColumnsEditor.Click;
  end;
end;

procedure TFormMain.GamesTreeViewCompareNodes(Sender: TBaseVirtualTree;
  Node1, Node2: PVirtualNode; Column: TColumnIndex; var Result: Integer);
var
  Data1, Data2: pGameInfo;
begin
  Data1:= Sender.GetNodeData(Node1);
  Data2:= Sender.GetNodeData(Node2);
  case Column of
    00: Result:= CompareText(Data1.eDescription, Data2.eDescription);
    01: Result:= CompareText(Data1.eYear, Data2.eYear);
    02: Result:= CompareText(Data1.eManufacturer, Data2.eManufacturer);
    03: Result:= CompareText(aAudioChannels[Data1.eAudioChannels], aAudioChannels[Data2.eAudioChannels]);
    04: Result:= CompareText(aAudioSamples[Data1.eAudioSamples], aAudioSamples[Data2.eAudioSamples]);

    05: Result:= CompareText(IntToStr(Data1.eNumberScreens), IntToStr(Data2.eNumberScreens));
    06: Result:= CompareText(aScreenType[Data1.eScreenType1], aScreenType[Data2.eScreenType1]);
    07: Result:= CompareText(MountOrientation(Data1.eScreenRotation1), MountOrientation(Data2.eScreenRotation1));
    08: Result:= CompareText(MountResolution(Data1.eResolutionWidth1, Data1.eResolutionHeight1, Data1.eScreenRotation1),
                             MountResolution(Data2.eResolutionWidth1, Data2.eResolutionHeight1, Data2.eScreenRotation1));
    09: Result:= CompareText(Data1.eRefreshRate1, Data2.eRefreshRate1);

    10: Result:= CompareText(aScreenType[Data1.eScreenType2], aScreenType[Data2.eScreenType2]);
    11: Result:= CompareText(MountOrientation(Data1.eScreenRotation2), MountOrientation(Data2.eScreenRotation2));
    12: Result:= CompareText(MountResolution(Data1.eResolutionWidth2, Data1.eResolutionHeight2, Data1.eScreenRotation2),
                             MountResolution(Data2.eResolutionWidth2, Data2.eResolutionHeight2, Data2.eScreenRotation2));
    13: Result:= CompareText(Data1.eRefreshRate2, Data2.eRefreshRate2);

    14: Result:= CompareText(aScreenType[Data1.eScreenType3], aScreenType[Data2.eScreenType3]);
    15: Result:= CompareText(MountOrientation(Data1.eScreenRotation3), MountOrientation(Data2.eScreenRotation3));
    16: Result:= CompareText(MountResolution(Data1.eResolutionWidth3, Data1.eResolutionHeight3, Data1.eScreenRotation3),
                             MountResolution(Data2.eResolutionWidth3, Data2.eResolutionHeight3, Data2.eScreenRotation3));
    17: Result:= CompareText(Data1.eRefreshRate3, Data2.eRefreshRate3);

    18: Result:= CompareText(aScreenType[Data1.eScreenType4], aScreenType[Data2.eScreenType4]);
    19: Result:= CompareText(MountOrientation(Data1.eScreenRotation4), MountOrientation(Data2.eScreenRotation4));
    20: Result:= CompareText(MountResolution(Data1.eResolutionWidth4, Data1.eResolutionHeight4, Data1.eScreenRotation4),
                             MountResolution(Data2.eResolutionWidth4, Data2.eResolutionHeight4, Data2.eScreenRotation4));
    21: Result:= CompareText(Data1.eRefreshRate4, Data2.eRefreshRate4);

    22: Result:= CompareText(aStatus[Data1.eDriverStatus], aStatus[Data2.eDriverStatus]);
    23: Result:= CompareText(aStatus[Data1.eEmulationStatus], aStatus[Data2.eEmulationStatus]);
    24: Result:= CompareText(aStatus[Data1.eColorStatus], aStatus[Data2.eColorStatus]);
    25: Result:= CompareText(aStatus[Data1.eColorStatus], aStatus[Data2.eSoundStatus]);
    26: Result:= CompareText(aStatus[Data1.eGraphicStatus], aStatus[Data2.eGraphicStatus]);
    27: Result:= CompareText(aStatus[Data1.eCocktailStatus], aStatus[Data2.eCocktailStatus]);
    28: Result:= CompareText(aStatus[Data1.eProtectionStatus], aStatus[Data2.eProtectionStatus]);

    29: Result:= CompareText(Data1.eCategory, Data2.eCategory);
    30: Result:= CompareText(Data1.eVersionAdded, Data2.eVersionAdded);
    31: Result:= CompareText(Data1.eName, Data2.eName);
    32: Result:= CompareText(Data1.eClone, Data2.eClone);
    33: Result:= CompareText(Data1.eDriverName, Data2.eDriverName);
    34: Result:= CompareText(Data1.eMerged, Data2.eMerged);
    35: Result:= CompareText(Data1.ePlayTime, Data2.ePlayTime);
    36: Result:= CompareText(IntToStr(Data1.ePlayed), IntToStr(Data2.ePlayed));
    37: Result:= CompareText(Data1.eNumberPlayers, Data2.eNumberPlayers);
    38: Result:= CompareText(aControlType[Data1.eControlType, 0], aControlType[Data2.eControlType, 0]);
    39: Result:= CompareText(aSaveState[Data1.eSaveState], aSaveState[Data2.eSaveState]);
  end;
end;

procedure TFormMain.GamesTreeViewFreeNode(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
var
  Data: pGameInfo;
begin
  Data:= Sender.GetNodeData(Node);
  Finalize(Data^);
end;

procedure TFormMain.GamesTreeViewChange(Sender: TBaseVirtualTree;
  Node: PVirtualNode);
begin
  if (Sender.SelectedCount = 1) and (Sender.Visible) then
     begin
       if SelectedNode <> Node then
          SelectedNode:= Node;
       if GetGameData(SelectedNode) then
          begin
            SelectedGameID[ButtonGameFilterArcade.Tag]:= GameInfoData.eROMIdentification;
            SelectedGameName[ButtonGameFilterArcade.Tag]:= GameInfoData.eName;
            GetSystemID(GameInfoData.eROMIdentification);
          end;
       if FormPreferences.PlayAudio.Checked then
          begin
            if GameInfoData <> nil then
               LoadSound(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone);
          end;
       if MenuShowImages.Checked and (not ButtonShowMAWSGameInfo.Checked) then
          begin
            case FormPreferences.PlayMNG.Checked of
              True:
                begin

                end;
              False:
                begin
                  ImageNumber:= 1;
                  ButtonNextImage.Tag:= 1;
                  if GameInfoData <> nil then
                     begin
                       DisplayImage(GameInfoData.eROMIdentification, GameInfoData.eName, GameInfoData.eClone, Images, ImageType, True, 1);
                     end;
                  UpdateLabelImages;
                end;
            end;
            if (not ProcessingAutomaticMAMEInfoDAT) and (PopupAutomaticGameInformation.Checked) then
               ShowGameInfoAll(0, True);
          end
       else
       if ButtonShowMAWSGameInfo.Checked and PanelWebBrowser.Visible then
          begin
            WebBrowser.Navigate(Format('http://www.mameworld.net/maws/romset/%s', [GameInfoData.eName]));
          end
       else
       if (not ProcessingAutomaticMAMEInfoDAT) and (PopupAutomaticGameInformation.Checked) then
          ShowGameInfoAll(0, True);
       UpdateStatusBarGame;
     end;
end;

procedure TFormMain.ButtonGroupedBlendCloneIcons50PercentClick(Sender: TObject);
begin
  GamesTreeView.Refresh;
end;

procedure TFormMain.GamesTreeViewPaintText(Sender: TBaseVirtualTree;
  const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType);
var
  Data: pGameInfo;
begin
  Data:= Sender.GetNodeData(Node);
  case IsSystemEntry(Data.eDriverName) of
    False:
      begin
        if (Data.eDriverStatus = 2) and (Data.eDriverStatus <> -1) then
           TargetCanvas.Font:= PreliminaryFont.Font
        else
           begin
             case GameIsClone(Data.eClone) of
               True : TargetCanvas.Font:= CloneFont.Font;
               False: TargetCanvas.Font:= MasterFont.Font;
             end;
           end;
      end;
    True:
      begin
        if Column = 0 then
           begin
             TargetCanvas.Font.Color:= clBlack;
             TargetCanvas.Font.Name:= 'Segoe UI';
             TargetCanvas.Font.Size:= 12;
             TargetCanvas.Font.Style:= [fsItalic];
           end;
      end;
  end;
  if Sender.Selected[Node] then
     begin
       TargetCanvas.Font.Color:= clWhite;
       if FormPreferences.SelectedGameBoldFont.Checked then
          if not IsSystemEntry(Data.eDriverName) then
             TargetCanvas.Font.Style:= TargetCanvas.Font.Style+[fsBold];
     end;
end;

procedure TFormMain.GamesTreeViewIncrementalSearch(Sender: TBaseVirtualTree;
  Node: PVirtualNode; const SearchText: WideString; var Result: Integer);
var
  StringsText,
  EntryText: String;
  Data: pGameInfo;
begin
  StringsText:= SearchText;
  Data:= Sender.GetNodeData(Node);
  case MenuIncrementalSearch.Tag of
    0: EntryText:= Data.eDescription;
    1: EntryText:= Data.eName;
  end;
  Result := AnsiStrLIComp(PChar(StringsText), PChar(EntryText), Length(StringsText));
end;

procedure TFormMain.ButtonGroupedToggleExpandedClosedClick(Sender: TObject);
begin
  if not CheckTotalVisible(GamesTreeView) then
     Exit;
  GamesTreeView.BeginUpdate;
  case ButtonGroupedToggleExpandedClosed.Checked of
    True : GamesTreeView.FullExpand(nil);
    False: GamesTreeView.FullCollapse(nil);
  end;
  GamesTreeView.EndUpdate;
end;

procedure TFormMain.PopupMenuGamesListPopup(Sender: TObject);
var
  SystemFolderName: String;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;

  if GetGameData(SelectedNode) then
  begin
    PopupSelectParentGame.Enabled:= GameInfoData.eClone <> '';
    GetSystemID(GameInfoData.eROMIdentification);
    SystemFolderName:= GetSystemFolderName(GameInfoData.eROMIdentification);
    PopupAddToFavorites.Visible:= SelectedFilterName <> 'favorites';
    PopupDeleteFromFavorites.Visible:= SelectedFilterName = 'favorites';

    PopupAddGameParentalLock.Visible:= ValidateFile(FrontendPath+'ini_files\parental_lock.ini');
    if PopupAddGameParentalLock.Visible then
       PopupAddGameParentalLock.Enabled:= CheckSelected(GamesTreeView);

    PopupPlayCustom_ZiNc.Enabled:= SystemID_Number = 2;
    PopupCustomGameOptions.Enabled:= SystemID_Number in [1, 2, 4, 5, 6];

    PopupAuditSelectedGame.Enabled:= SystemID_Number in [1, 4, 5, 6];
    PopupAuditAllGamesMAME.Enabled:= not Assigned(FormAudit);
    PopupAuditAvailableGamesMAME.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAllGamesAGEMAME.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAvailableGamesAGEMAME.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAllGamesPinMAME.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAvailableGamesPinMAME.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAllGamesHazeMD.Enabled:= PopupAuditAllGamesMAME.Enabled;
    PopupAuditAvailableGamesHazeMD.Enabled:= PopupAuditAllGamesMAME.Enabled;

    PopupDeleteZIPFileName.Caption:= Format(PopupDeleteZIPFileName.Hint,
                                           [LowerCase(GameInfoData.eName)+'.zip']);

    PopupDeleteMultipleZipFileNames.Enabled:= VerifyMultiSelect;

    PopupDeleteAudioFileName.Caption:= Format(PopupDeleteAudioFileName.Hint,
                                             [LowerCase(GameInfoData.eName)]);
    PopupDeleteVideoFileName.Caption:= Format(PopupDeleteVideoFileName.Hint,
                                             [LowerCase(GameInfoData.eName)]);
    PopupDeleteCFGFile.Caption:= Format(PopupDeleteCFGFile.Hint,
                                       [LowerCase(GameInfoData.eName)+'.cfg']);
    PopupDeleteNVRAMFile.Caption:= Format(PopupDeleteNVRAMFile.Hint,
                                         [LowerCase(GameInfoData.eName)+'.nv']);
    PopupDeleteINPFile.Caption:= Format(PopupDeleteINPFile.Hint,
                                       [LowerCase(GameInfoData.eName)+'.inp']);
    PopupDeleteStateFile.Caption:= Format(PopupDeleteStateFile.Hint,
                                         [LowerCase(GameInfoData.eName)+'.sta']);

    PopupGameInformation.Enabled:= SystemID_Number = 1;
    PopupGameHistory.Enabled:= PopupGameInformation.Enabled;
    PopupGameDriverInformation.Enabled:= PopupGameInformation.Enabled;

    PopupReloadMAMu_Icons.Enabled:= PopupGamesUseMAMu_Icons.Checked;
  end;
end;

procedure TFormMain.MenuRandomGamePreviewClick(Sender: TObject);
var
  Loop, GameIndex: Integer;
  ValidGame: Boolean;

  function RandomizeColor: Boolean;
  begin
    Result:= Assigned(FormRandomGamePreviewPanel);
    if Result then
       begin
         FormRandomGamePreviewPanel.Color:= RGB(Random(255), Random(255), Random(255));
         FormRandomGamePreviewPanel.LabelTitle.Font.Color:= RGB(Random(255), Random(255), Random(255));
       end;
  end;

  function ClosePreviewPanel: Boolean;
  begin
    FormRandomGamePreviewPanel.Close;
    FreeAndNil(FormRandomGamePreviewPanel);
    if FormPreferences.RestoreSelectedGame.Checked then
       SelectNode(MenuRandomGamePreview.Tag);
  end;

  function PauseProccess(MaxTime: Integer): Boolean;
  var
    StartTick, CurrentTick, RandomTick: Integer;
  begin
    Result:= MenuRandomGamePreview.Checked;
    if Result then
       begin
         StartTick:= GetTickCount;
         RandomTick:= StartTick;
         if Assigned(FormRandomGamePreviewPanel) then
            begin
              FormRandomGamePreviewPanel.LabelTotalPause.Caption:= '/ '+GetPlayTime(MaxTime, False, False);
              FormRandomGamePreviewPanel.LabelTotalPause2.Caption:= FormRandomGamePreviewPanel.LabelTotalPause.Caption;
            end;
         repeat
           Sleep(100);
           CurrentTick:= GetTickCount;
           if FormPreferences.WarningPanelAnimation.Checked then
              begin
                if (CurrentTick-RandomTick) >= 1000 then
                   begin
                     RandomizeColor;
                     RandomTick:= CurrentTick;
                   end;
              end;

           if Assigned(FormRandomGamePreviewPanel) then
              begin
                FormRandomGamePreviewPanel.LabelPause.Caption:= GetPlayTime((CurrentTick-StartTick), False, False);
                FormRandomGamePreviewPanel.LabelPause2.Caption:= FormRandomGamePreviewPanel.LabelPause.Caption;
              end;
           Application.ProcessMessages;
         until ((CurrentTick-StartTick) >= MaxTime) or (not MenuRandomGamePreview.Checked);
         if not MenuRandomGamePreview.Checked then
            begin
              Result:= False;
              ClosePreviewPanel;
            end;
       end;
  end;

begin
  case MenuRandomGamePreview.Checked of
    True:
      begin
        if GenerateMessage('Random Game Preview', '  This feature will run random games in a '+
                           'period of time, based on the settings from preferences screen, or '+
                           'until you disable it. '+ 'Please do not try to run any other game or '+
                           'do anything else in the frontend while the random game preview is being '+
                           'executed.'+#13#10+'  Also, be aware that multimedia features may not '+
                           'work correctly, causing Emu Loader to crash or malfunction...'+#13#10+#13#10+
                           'Continue ?', 1) = mrNo then
           begin
             MenuRandomGamePreview.Click;
             Exit;
           end;

        if FormPreferences.RestoreSelectedGame.Checked then
           MenuRandomGamePreview.Tag:= SelectedNode.Index;
           
        if FormPreferences.NumberGamesToRun.Position = 2 then
           GameIndex:= 0
        else
           GameIndex:= FormPreferences.NumberGamesToRun.Position-1;

        if not Assigned(FormRandomGamePreviewPanel) then
           FormRandomGamePreviewPanel:= TFormRandomGamePreviewPanel.Create(nil);
        FormRandomGamePreviewPanel.AlphaBlend:= Win32Platform = 2;
        if FormRandomGamePreviewPanel.AlphaBlend then
           FormRandomGamePreviewPanel.AlphaBlendValue:= FormPreferences.BlendPreviewWindowFactor.Position;
        FormRandomGamePreviewPanel.Show;
        Randomize;
        RandomizeColor;
        FormMain.BringToFront;
        repeat
          ValidGame:= False;
          for Loop:=1 to FormPreferences.UseAvailableGamesOnly.Position do
          begin
            ButtonRandomGame.Click;
            case GetGameData(SelectedNode) of
              True:
                begin
                  ValidGame:= (GameInfoData.eROMIdentification in [00..03, 06, 07, 10, 11, 14..16, 20..22, 26, 27]);
                  if ValidGame then
                     Break;
                end;
              False:
                begin
                  GameIndex:= 1;
                  Break;
                end;
            end;
          end;
          Application.ProcessMessages;
          case ValidGame of
            True:
              begin
                case PauseProccess(FormPreferences.PauseBeforeEmulatorStarts.Position)of
                  True:
                    begin
                      if MenuRandomGamePreview.Checked then
                         begin
                           ExecuteGame(0);
                           if FormPreferences.NumberGamesToRun.Position <> 2 then
                              Dec(GameIndex);
                         end;
                      if GameIndex <> -1 then
                         begin
                           if not PauseProccess(FormPreferences.PauseBetweenGames.Position) then
                              Exit;
                         end;
                    end;
                  False: Exit;
                end;
              end;
            False:
              begin
                GenerateMessage('Random Game Preview', 'No available games were found after '+
                                IntToStr(FormPreferences.UseAvailableGamesOnly.Position)+' retries. Aborting...', 2);
                ClosePreviewPanel;
                MenuRandomGamePreview.Click;
                Exit;
              end;
          end;
          RandomizeColor;
        until (not MenuRandomGamePreview.Checked) or (GameIndex = -1);
        ClosePreviewPanel;
        MenuRandomGamePreview.Click;
      end;
    False:
      begin
        // nothing
      end;
  end;
end;

procedure TFormMain.WebButtonStopClick(Sender: TObject);
begin
  WebBrowser.Stop;
end;

procedure TFormMain.WebButtonRefreshClick(Sender: TObject);
begin
  WebBrowser.Refresh;
end;

procedure TFormMain.WebBrowserProgressChange(Sender: TObject; Progress,
  ProgressMax: Integer);
begin
  WebProgressBar.Max:= ProgressMax;
  WebProgressBar.Position:= Progress;
end;

procedure TFormMain.ZipForgeOverallProgress(Sender: TObject;
  Progress: Double; Operation: TZFProcessOperation;
  ProgressPhase: TZFProgressPhase; var Cancel: Boolean);
begin
  if Operation = poExtract then
     begin
       if FormStatus.Visible then
          begin
            FormStatus.ProgressBar.Progress:= Trunc(Progress);
            Application.ProcessMessages;
          end;
       if CancelCurrentOperation then
          Cancel:= True;
     end;
end;

procedure TFormMain.WebBrowserStatusTextChange(Sender: TObject;
  const Text: WideString);
begin
  WebStatusBar.SimpleText:= Text;
end;

procedure TFormMain.ButtonShowMAWSGameInfoClick(Sender: TObject);
begin
  NotebookImages.PageIndex:= Ord(ButtonShowMAWSGameInfo.Checked);
  case ButtonShowMAWSGameInfo.Checked of
    True:
      begin
        case CheckSelected(GamesTreeView) of
          True:
            begin
              if MenuShowImages.Checked then
                 Images.Bitmap.Clear;
              if Assigned(FormTextViewer) then
                 FormTextViewer.Visible:= False;
              if ButtonShowMAWSGameInfo.Tag = 1 then
                 ButtonShowMAWSGameInfo.Tag:= 0;
              if not PanelScreenshotsArea.Visible then
                 begin
                   PanelScreenshotsArea.Visible:= True;
                   Splitter.Visible:= True;
                 end;
              if GetGameData(SelectedNode) then
                 WebBrowser.Navigate(Format('http://www.mameworld.net/maws/romset/%s', [GameInfoData.eName]));
            end;
          False:
            begin
              if ButtonShowMAWSGameInfo.Tag = 0 then
                 ButtonShowMAWSGameInfo.Checked:= False;
            end;
        end;
      end;
    False:
      begin
        if WebBrowser.Busy then
           WebBrowser.Stop;
        case MenuShowImages.Checked of
          True:
            begin
              Images.Hint:= 'maws_exit';
              MenuShowImages.OnClick(Self);
            end;
          False:
            begin
              case Assigned(FormTextViewer) of
                True: FormTextViewer.Visible:= True;
                False:
                  begin
                    PanelScreenshotsArea.Visible:= MAMEInfoTextHolder.Visible;
                    Splitter.Visible:= MAMEInfoTextHolder.Visible;
                  end;
              end;
            end;
        end;
      end;
  end;
  FocusGamesList;
end;

procedure TFormMain.ButtonShowGameSnapshotsClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonImagesViewMode.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       if GamesTreeView.Tag = 1 then
          Exit;
     end;
  SetImageMode(TMenuItem(Sender).Tag);
end;

procedure TFormMain.PopupShowFirstImageClick(Sender: TObject);
begin
  ImageNumber:= 1;
  MenuShowImages.OnClick(Self);
end;

procedure TFormMain.PopupRenameCurrentImageClick(Sender: TObject);
var
  Result: String;
begin
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  
  Result:= InputBoxEL('Rename Image', 'Enter new filename:', ExtractFileName(ImageDetails[1].FileName));
  if LowerCase(Result) <> LowerCase(ExtractFileName(ImageDetails[1].FileName)) then
     begin
       if ImageDetails[1].ZipFileName = '' then
          RenameFile(ImageDetails[1].FileName, ExtractFilePath(ImageDetails[1].FileName)+Result)
       else
          begin
            case FileExists(ImageDetails[1].ZipFileName) of
              True:
                begin
                  RenameFileInsideZip(ImageDetails[1].ZipFileName, ImageDetails[1].FileName, Result);
                  ZipForge.CloseArchive;
                end;
              False:
                begin
                  GenerateMessage('Error', Format('File "%s" not found! Failed to rename image.',
                                         [ImageDetails[1].ZipFileName]), 2);
                end;
            end;
            ShowZipErrors;
          end;
       MenuShowImages.OnClick(Self);
     end;
end;

procedure TFormMain.PopupDeleteCurrentImageClick(Sender: TObject);
var
  strMessage: String;
begin
  if not GetGameData(SelectedNode) then
     Exit;
  if ImageDetails[1].ZipFileName = '' then
     strMessage:= Format('Delete image "%s". Are you sure ?', [ImageDetails[1].FileName])
  else
     strMessage:= Format('Delete image "%s" ["%s]. Are you sure ?', [ImageDetails[1].FileName, ImageDetails[1].ZipFileName]);
  if GenerateMessage('Delete Image', strMessage, 1) = mrYes then
     begin
       if ImageDetails[1].ZipFileName = '' then
          DeleteFile(ImageDetails[1].FileName)
       else
          begin
            DeleteFileInsideZip(ImageDetails[1].ZipFileName, ImageDetails[1].FileName);
            ShowZipErrors;
          end;
       MenuShowImages.OnClick(Self);
     end;
end;

procedure TFormMain.PopupDeleteZIPFileNameClick(Sender: TObject);
var
  ZIPFileName, ZIPFolderName, DeleteMessage, EmuTitle: String;
  MergedGame, DeleteFileName: Boolean;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;

  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  SetCurrentDir(ExtractFilePath(EmulatorFile[SystemID_Number]));
  ZIPFileName:= GameInfoData.eName;
  ZIPFolderName:= SearchZIPFolder(ZIPFileName, GameInfoData.eROMIdentification);
  if ZIPFolderName = '' then
     begin
       MergedGame:= (GameInfoData.eMerged <> '') and (SystemID_Number in [1, 4, 5, 6]);
       case MergedGame of
         True:
          begin
             // this is a merged game
             ZIPFileName:= GameInfoData.eClone;
             ZIPFolderName:= SearchZIPFolder(ZIPFileName, mROMIdentification);
             if ZIPFolderName = '' then
                begin
                  // Parent filename not found
                  GenerateMessage('File Not Found', 'There is no file to delete! Try selecting a different emulator.', 2);
                  Exit;
                end
             else
                DeleteFileName:= True; // Parent filename found
           end;
         False:
           begin
             GenerateMessage('File Not Found', 'There is no file to delete! Try selecting a different emulator.', 2);
             Exit;
           end;
       end;
     end
  else
     DeleteFileName:= True; // ZIP filename found

  if DeleteFileName then
     begin
       case MergedGame of
         False:
           begin
             case GameIsClone(GameInfoData.eClone) of
               True : DeleteMessage:= Format('This will physically delete the file "%s" from disk! Are you sure ?', [ZIPFolderName]);
               False: DeleteMessage:= Format('This will physically delete the file "%s" from disk! If there are clones of this game, they will stop working. Are you sure ?', [ZIPFolderName])
             end;
           end;
         True: DeleteMessage:= Format('This will physically delete the file "%s" from disk! The game "%s" is merged, which means that the parent game will also be lost. Are you sure ?', [ZIPFolderName, GameInfoData.eName]);
       end;

       EmuTitle:= '['+GetSystemIniSection(SystemID_Number)+']';
       if GenerateMessage(PopupDeleteZIPFileName.Caption+EmuTitle, DeleteMessage, 1, True) = mrYes then
          begin
            DeleteFile(ZIPFolderName);
            PopupRefreshSelectedGame.OnClick(Self);
          end;
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.PopupDeleteAudioFileNameClick(Sender: TObject);
var
  AudioFolder: String;
  AudioActive: Boolean;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  AudioActive:= FormPreferences.PlayAudio.Checked;
  AudioFolder:= IncludeTrailingPathDelimiter(AudioFolders[SystemID_Number]);
  AudioFolder:= IncludeTrailingPathDelimiter(AudioFolder);
  SetCurrentDir(FrontendPath);
  if GenerateMessage(PopupDeleteAudioFileName.Caption, Format('All files (.mp3; .wav; .ogg) of game '+
                     '"%s", system "%s" will be deleted! Are you sure ?', [GameInfoData.eName,
                     GetSystemFolderName(GameInfoData.eROMIdentification)]), 1, True) = mrYes then
     begin
       if AudioActive then
          FormPreferences.PlayAudio.Checked:= False;

       DeleteFile(AudioFolder+GameInfoData.eName+'.mp3');
       DeleteFile(AudioFolder+GameInfoData.eName+'.wav');
       DeleteFile(AudioFolder+GameInfoData.eName+'.ogg');
       if AudioActive then
          FormPreferences.PlayAudio.Checked:= True;
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.PopupDeleteVideoFileNameClick(Sender: TObject);
var
  VideoFolderStr: String;
  VideoActive: Boolean;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  VideoActive:= FormPreferences.PlayMNG.Checked;
  VideoFolderStr:= IncludeTrailingPathDelimiter(MNGFolders[SystemID_Number]);
  VideoFolderStr:= IncludeTrailingPathDelimiter(VideoFolderStr);
  SetCurrentDir(FrontendPath);
  if GenerateMessage(PopupDeleteVideoFileName.Caption, Format('MNG animation of game '+
                     '"%s", system "%s" will be deleted! Are you sure ?', [GameInfoData.eName,
                     GetSystemFolderName(GameInfoData.eROMIdentification)]), 1, True) = mrYes then
     begin
       if VideoActive then
          FormPreferences.PlayMNG.Checked:= False;

       DeleteFile(VideoFolderStr+GameInfoData.eName+'.mng');
       if VideoActive then
          FormPreferences.PlayMNG.Checked:= True;
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
end;

procedure TFormMain.PopupDeleteCFGFileClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;

  GetSystemID(GameInfoData.eROMIdentification);
  if (SystemID_Number in [1, 4, 5, 6]) then
     begin
       case TMenuItem(Sender).Tag of
         0: CallDeleteFile(GameInfoData.eName+'.cfg', 'cfg');
         1: CallDeleteFile(GameInfoData.eName+'.nv', 'nvram');
         2: CallDeleteFile(GameInfoData.eName+'.inp', 'input');
         3: CallDeleteFile(GameInfoData.eName+'.sta', 'state');
       end;
     end;
end;

procedure TFormMain.LoadTopBar(ImageHolder: TImage32; FileName: String);
begin
  if FileExists(FrontendPath+'resources\images\topbars\'+FileName) then
     ImageHolder.Bitmap.LoadFromFile(FrontendPath+'resources\images\topbars\'+FileName);
end;

procedure TFormMain.PopupCheckMissingIconsClick(Sender: TObject);
type
  TGameInfoArray = array of TGameInfo;
var
  Loop: Integer;
  Folder, ZipFile, System: String;
  SearchIcon, IsCloneGame, UseZIPFile, IconIsFound, grayBkColor: Boolean;
  NoIconsList, el_GamesList: THashedStringList;
  mamu_GamesList: TGameInfoArray;
  MissingGamesCount, SystemGamesCount: packed array of Integer;
  lastSystemID: ShortInt;
begin
  if not CheckTotal(GamesTreeView) then
     Exit;

  if not Assigned(FormMAMu_MaintenanceSettings) then
     FormMAMu_MaintenanceSettings:= TFormMAMu_MaintenanceSettings.Create(nil);
  LoadMAMu_SettingsIcons(FormMAMu_MaintenanceSettings.IL_Settings);
  FormMAMu_MaintenanceSettings.LabelDescription.Caption:= FixCaption(PopupCheckMissingIcons.Caption)+'.';
  FormMAMu_MaintenanceSettings.ShowModal;

  if FormMAMu_MaintenanceSettings.Tag = 1 then
     begin
       FreeAndNil(FormMAMu_MaintenanceSettings);
       Exit;
     end;

  Application.ProcessMessages;
  FormStatus.Show;
  FormStatus.LabelStatusType.Caption:= FixCaption(PopupCheckMissingIcons.Caption);
  FormStatus.LabelMessage.Caption:= 'Parsing files.';
  FormStatus.ProgressBar.Progress:= 0;
  FormStatus.Refresh;
  SetLength(MissingGamesCount, MaxArcadeSystems);
  SetLength(SystemGamesCount, MaxArcadeSystems);
  for Loop:=0 to MaxArcadeSystems-1 do
  begin
    MissingGamesCount[Loop]:= 0;
    SystemGamesCount[Loop]:= 0;
  end;
  Screen.Cursor:= crHourGlass;

  case FormMAMu_MaintenanceSettings.SettingsList.Items[1].Checked of
    True : Folder:= GetZipFolderFull(30);
    False: Folder:= '';
  end;
  UseZIPFile:= FormMAMu_MaintenanceSettings.SettingsList.Items[2].Checked;
  case UseZIPFile of
    True:
      begin
        ZipFile:= VerifyZipType(FormPreferences.MAMu_Icons.Text, False);
        if LowerCase(ExtractFileName(ZipFile)) = 'dummy.zip' then
           ZipFile:= '';
        UseZIPFile:= FileExists(Folder+ZipFile);
        if UseZIPFile then
           begin
             ListROMsName:= THashedStringList.Create;
             ListROMsNameFullPath:= THashedStringList.Create;
             UseZIPFile:= GetContents(Folder+ZipFile, True, False);
           end;
      end;
    False: ZipFile:= '';
  end;

  el_GamesList:= THashedStringList.Create;
  if FormMAMu_MaintenanceSettings.SettingsList.Items[3].Checked then
     GetGamesList(el_GamesList, 1); // MAME
  if FormMAMu_MaintenanceSettings.SettingsList.Items[4].Checked then
     GetGamesList(el_GamesList, 2); // ZiNc
  if FormMAMu_MaintenanceSettings.SettingsList.Items[5].Checked then
     GetGamesList(el_GamesList, 3); // Daphne
  if FormMAMu_MaintenanceSettings.SettingsList.Items[6].Checked then
     GetGamesList(el_GamesList, 4); // AGEMAME
  if FormMAMu_MaintenanceSettings.SettingsList.Items[7].Checked then
     GetGamesList(el_GamesList, 5); // PinMAME
  if FormMAMu_MaintenanceSettings.SettingsList.Items[8].Checked then
     GetGamesList(el_GamesList, 6); // HazeMD

  // sort list and group games by system
  FormStatus.LabelMessage.Caption:= 'Sorting games by system.';
  FormStatus.Refresh;
  SetLength(mamu_GamesList, el_GamesList.Count);
  FormStatus.ProgressBar.Progress:= el_GamesList.Count-1;
  grayBkColor:= False;
  for Loop:=0 to el_GamesList.Count-1 do
  begin
    ClearMemoryColumnsVariables;
    GetROMFields(el_GamesList, Loop);
    with mamu_GamesList[Loop] do
    begin
      eROMIdentification:= mROMIdentification;
      eDescription:= mDescription;
      eName:= mName;
      eClone:= mClone;
    end;
    FormStatus.ProgressBar.Progress:= Loop;
  end;
  FormStatus.LabelMessage.Caption:= 'Searching for icons.';
  FormStatus.Refresh;
  lastSystemID:= -1;
  NoIconsList:= THashedStringList.Create;
  FormStatus.ProgressBar.Progress:= Length(mamu_GamesList)-1;
  for Loop:=0 to Length(mamu_GamesList)-1 do
  begin
    GetSystemID(mamu_GamesList[Loop].eROMIdentification);
    IsCloneGame:= GameIsClone(mamu_GamesList[Loop].eClone);
    case IsCloneGame of
      True : SearchIcon:= FormMAMu_MaintenanceSettings.SettingsList.Items[0].Checked;
      False: SearchIcon:= True;
    end;
    if SearchIcon then
       begin
         Inc(SystemGamesCount[SystemID_Number]);
         System:= GetSystemFolderName(mamu_GamesList[Loop].eROMIdentification);
         if System = 'mame' then
            System:= ''
         else
            System:= System+'\';

         IconIsFound:= False;

         if FormMAMu_MaintenanceSettings.SettingsList.Items[1].Checked then
            IconIsFound:= FileExists(Folder+System+mamu_GamesList[Loop].eName+'.ico'); // search unzipped icon

         if (FormMAMu_MaintenanceSettings.SettingsList.Items[2].Checked) and UseZIPFile and (not IconIsFound) then
            IconIsFound:= ListROMsNameFullPath.IndexOf(System+mamu_GamesList[Loop].eName+'.ico') <> -1;

         if not (IconIsFound) then
            begin
              //if CurrentSystem <> System then
              //   begin
              if SystemID_Number <> lastSystemID then
                 begin
                   // new system, new games count, new section in html
                   if lastSystemID <> -1 then
                      begin
                        NoIconsList.Add('  <tr>');
                        NoIconsList.Add('    <td width="800" colspan="3" bgcolor="#3399FF"><font face="Segoe UI">'+
                                        '<b>&nbsp;&nbsp;&nbsp;&nbsp;Games Scanned: '+IntToStr(SystemGamesCount[lastSystemID])+'<br>'+
                                        '&nbsp;&nbsp;&nbsp;&nbsp;Missing Icons: '+IntToStr(MissingGamesCount[lastSystemID])+'</br></td>');
                        NoIconsList.Add('  </tr>');
                        NoIconsList.Add('</table><p>');
                      end;
                   lastSystemID:= SystemID_Number;
                   NoIconsList.Add('<table border="0" cellspacing="0" width="800" style="border-collapse: collapse">');
                   NoIconsList.Add('  <tr>');
                   NoIconsList.Add('    <td width="800" colspan="3"><i><font face="Segoe UI" color="#FF0000"><b>'+GetEmuFullDescription(SystemID_Number)+' Games</b></font></i></td>');
                   NoIconsList.Add('  </tr>');
                   NoIconsList.Add('  <tr>');
                   case FormMAMu_MaintenanceSettings.SettingsList.Items[0].Checked of
                     True : NoIconsList.Add('    <td width="450" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Description</b></td>');
                     False: NoIconsList.Add('    <td width="625" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Description</b></td>');
                   end;
                   NoIconsList.Add('    <td width="175" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Game Name</b></td>');
                   if FormMAMu_MaintenanceSettings.SettingsList.Items[0].Checked then
                      NoIconsList.Add('    <td width="175" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Clone of</b></td>');
                   NoIconsList.Add('  </tr>');
                 end;
              Inc(MissingGamesCount[SystemID_Number]);
              NoIconsList.Add('  <tr>');
              case grayBkColor of
                True:
                  begin
                    NoIconsList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+mamu_GamesList[Loop].eDescription+'</td>');
                    NoIconsList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+mamu_GamesList[Loop].eName+'</td>');
                  end;
                False:
                  begin
                    NoIconsList.Add('    <td><font face="Segoe UI">'+mamu_GamesList[Loop].eDescription+'</td>');
                    NoIconsList.Add('    <td><font face="Segoe UI">'+mamu_GamesList[Loop].eName+'</td>');
                  end;
              end;

              if FormMAMu_MaintenanceSettings.SettingsList.Items[0].Checked then
                 begin
                   case grayBkColor of
                     True : NoIconsList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+mamu_GamesList[Loop].eClone+'</td>');
                     False: NoIconsList.Add('    <td><font face="Segoe UI">'+mamu_GamesList[Loop].eClone+'</td>');
                   end;
                 end;
              NoIconsList.Add('  </tr>');
              grayBkColor:= not grayBkColor;
            end;
       end;
    FormStatus.ProgressBar.Progress:= Loop;
  end;
  if MissingGamesCount[SystemID_Number] > 0 then
     begin
       NoIconsList.Add('  <tr>');
       NoIconsList.Add('    <td width="800" colspan="3" bgcolor="#3399FF"><font face="Segoe UI">'+
                       '<b>&nbsp;&nbsp;&nbsp;&nbsp;Games Scanned: '+IntToStr(SystemGamesCount[SystemID_Number])+'<br>'+
                       '&nbsp;&nbsp;&nbsp;&nbsp;Missing Icons: '+IntToStr(MissingGamesCount[SystemID_Number])+'</br></td>');
       NoIconsList.Add('  </tr>');
       NoIconsList.Add('</table><p>');
     end;

  FreeAndNil(ListROMsName);
  FreeAndNil(ListROMsNameFullPath);

  for Loop:=Length(mamu_GamesList)-1 downto 0 do
      Finalize(mamu_GamesList[Loop]);

  FormStatus.Close;
  Screen.Cursor:= crDefault;
  if NoIconsList.Count > 0 then
     begin
       NoIconsList.Insert(0, '<p align="center"><font face="Segoe UI" color="#FF0000" size="3"><b>Missing Games Icons</b></font></p>');
       NoIconsList.Add('</table><p>');
       NoIconsList.Add('<p><font face="Segoe UI" size="2"><b>Search Path: '+Folder);
       if UseZIPFile then
          NoIconsList.Add('<br>Zip File: '+Folder+ZipFile);
       NoIconsList.Add('<br></b><font color="#008000">Generated by Emu Loader v'+
                       GetFileInfo(Application.ExeName, VersionInfo[3])+'<br>Date: '+
                       DateToStr(Date)+' - Time: '+TimeToStr(Time)+'</font></font></p>');

       if GamesListSaveDialog.Execute then
          NoIconsList.SaveToFile(GamesListSaveDialog.Filename);
     end;
  FreeAndNil(NoIconsList);
  FreeAndNil(FormMAMu_MaintenanceSettings);
  FreeAndNil(NoIconsList);
  FreeAndNil(el_GamesList);
end;

procedure TFormMain.PopupCheckNotUsedIconsClick(Sender: TObject);
var
  NotUsedIconsList, GamesListDAT, IcoFilesList: THashedStringList;
  Loop, FileIndex, NotUsedIconsCount: Integer;
  Folder, ZipFile, System, tempString: String;
  UseZIPFile: Boolean;
begin
  Screen.Cursor:= crHourGlass;
  FormStatus.Show;
  FormStatus.LabelStatusType.Caption:= FixCaption(PopupCheckNotUsedIcons.Caption);
  FormStatus.LabelMessage.Caption:= 'Creating icons files list.';
  FormStatus.ProgressBar.Progress:= 0;
  FormStatus.Refresh;
  Folder:= GetZipFolderFull(30);
  ZipFile:= VerifyZipType(FormPreferences.MAMu_Icons.Text, False);
  if ZipFile = 'dummy.zip' then
     ZipFile:= 'icons.zip';

  IcoFilesList:= THashedStringList.Create;
  GetFilesList(Folder, '.???', '*.*', IcoFilesList, True, False, True);
  FormStatus.LabelMessage.Caption:= 'Parsing files.';
  FormStatus.Refresh;
  if IcoFilesList.Count > 0 then
     begin
       IcoFilesList.BeginUpdate;
       for Loop:=0 to IcoFilesList.Count-1 do
       begin
         tempString:= IcoFilesList[Loop];
         Delete(tempString, 1, Length(Folder));
         icoFilesList[Loop]:= tempString;
       end;
       IcoFilesList.EndUpdate;
       Application.ProcessMessages;
       Screen.Cursor:= crHourGlass;
       GamesListDAT:= THashedStringList.Create;
       GetGamesList(GamesListDAT, 1);
       GetGamesList(GamesListDAT, 2);
       GetGamesList(GamesListDAT, 3);
       GetGamesList(GamesListDAT, 4);
       GetGamesList(GamesListDAT, 5);
       GetGamesList(GamesListDAT, 6);
       GamesListDAT.BeginUpdate;
       for Loop:=0 to GamesListDAT.Count-1 do
       begin
         GetROMFields(GamesListDAT, Loop);
         System:= GetSystemFolderName(mROMIdentification);
         if System = 'mame' then
            System:= ''
         else
            System:= System+'\';
         GamesListDAT[Loop]:= LowerCase(System+mName)+'.ico';
       end;
       GamesListDAT.Sort;
       GamesListDAT.EndUpdate;

       NotUsedIconsCount:= 0;
       NotUSedIconsList:= THashedStringList.Create;
       NotUsedIconsList.BeginUpdate;

       FormStatus.LabelMessage.Caption:= 'Scanning unzipped files.';
       FormStatus.Refresh;
       FormStatus.ProgressBar.MaxValue:= IcoFilesList.Count-1;
       for Loop:=0 to IcoFilesList.Count -1 do
       begin
         FileIndex:= GamesListDAT.IndexOf(LowerCase(IcoFilesList[Loop]));
         if (FileIndex = -1) and Boolean(ExtractFileExt(IcoFilesList[Loop]) <> '.zip') then
            begin
              // file not found in games list, will add to the unneeded files list
              Inc(NotUsedIconsCount);
              NotUsedIconsList.Add('<tr>');
              NotUsedIconsList.Add('<td nowrap>'+IcoFilesList[Loop]+'</td>');
              NotUsedIconsList.Add('<td nowrap>'+Folder+IcoFilesList[Loop]+'</td>');
              NotUsedIconsList.Add('</tr>');
            end;
         FormStatus.ProgressBar.Progress:= Loop;
       end;
     end;
  FreeAndNil(IcoFilesList);

  UseZIPFile:= FileExists(Folder+ZipFile);
  if UseZIPFile then
     begin
       FormStatus.LabelMessage.Caption:= 'Scanning zipped files.';
       FormStatus.Refresh;
       ListROMsName:= THashedStringList.Create;
       ListROMsNameFullPath:= THashedStringList.Create;
       UseZIPFile:= GetContents(Folder+ZipFile, True, False);

       ListROMsNameFullPath.BeginUpdate;
       ListROMsNameFullPath.Sort;
       ListROMsNameFullPath.EndUpdate;
       FormStatus.ProgressBar.MaxValue:= ListROMsNameFullPath.Count-1;
       for Loop:=0 to ListROMsNameFullPath.Count-1 do
       begin
         FileIndex:= GamesListDAT.IndexOf(LowerCase(ListROMsNameFullPath[Loop]));
         if FileIndex = -1 then
            begin
              // file not found in games list, will add to the unneeded files list
              Inc(NotUsedIconsCount);
              NotUsedIconsList.Add('<tr>');
              NotUsedIconsList.Add('<td nowrap>'+ListROMsNameFullPath[Loop]+'</td>');
              NotUsedIconsList.Add('<td nowrap>'+Folder+ZipFile+'</td>');
              NotUsedIconsList.Add('</tr>');
            end;
         FormStatus.ProgressBar.Progress:= Loop;
       end;
     end;
  if Assigned(NotUsedIconsList) then
     NotUsedIconsList.EndUpdate;
  FormStatus.Close;
  Screen.Cursor:= crDefault;
  if Assigned(NotUsedIconsList) then
  if NotUsedIconsList.Count > 0 then
     begin
       NotUsedIconsList.Insert(0, '<p align="center"><font face="Segoe UI" color="#FF0000" size="3"><b>Not Used Games Icon Files</b></font></p>');
       NotUsedIconsList.Insert(1, '<table border="1" cellspacing="0" width="100%">');
       NotUsedIconsList.Insert(2, '<tr>');
       NotUsedIconsList.Insert(3, '<td nowrap BGCOLOR="#D4D0C8"><B>File Name</B></td>');
       NotUsedIconsList.Insert(4, '<td nowrap BGCOLOR="#D4D0C8"><B>File Path</B></td>');
       NotUsedIconsList.Insert(5, '</tr>');
       NotUsedIconsList.Add('</table><p>');
       NotUsedIconsList.Add('<p><font face="Segoe UI" size="2"><b>Search Path: '+Folder);
       if UseZIPFile then
          NotUsedIconsList.Add('<br>Scanned Zip File: '+ZipFile);
       NotUsedIconsList.Add('</p><p><font face="Segoe UI" size="2"><b>Total Files: '+IntToStr(NotUsedIconsCount)+
                            '<br></b><font color="#008000">Generated by Emu Loader v'+
                            GetFileInfo(Application.ExeName, VersionInfo[3])+
                            '<br>Date: '+DateToStr(Date)+' - Time: '+TimeToStr(Time)+'</font></p>');

       if GamesListSaveDialog.Execute then
          NotUsedIconsList.SaveToFile(GamesListSaveDialog.Filename);
     end;
  FreeAndNil(GamesListDAT);
  FreeAndNil(NotUsedIconsList);
  FreeAndNil(ListROMsName);
  FreeAndNil(ListROMsNameFullPath);
end;

procedure TFormMain.PopupAddToFavoritesClick(Sender: TObject);
begin
  AddToFavorite;
end;

procedure TFormMain.PopupDeleteFromFavoritesClick(Sender: TObject);
begin
  DeleteFromFavorite;
end;

procedure TFormMain.PopupAddGameParentalLockClick(Sender: TObject);
var
  NotAddedGames, GamesToAdd, GamesDescription, tempList: THashedStringList;
  Loop, GameIndex: Integer;
  AddToList: Boolean;
  SelNode: PVirtualNode;
  MultiSelectStr, plSystem: String;

  function VerifyGame: Boolean;
  begin
    if GetGameData(SelNode) then
       begin
         plSystem:= GetSystemFolderName(GameInfoData.eROMIdentification);
         if tempList.IndexOf(GameInfoData.eName+'='+plSystem) = -1 then
            begin
              GamesToAdd.Add(Format('%s=%s', [GameInfoData.eName, plsystem]));
              GamesDescription.Add(GameInfoData.eDescription);
            end
         else
            NotAddedGames.Add(Format('%s - [%s, %s]', [GameInfoData.eDescription, GameInfoData.eName, plSystem]));
       end
    else
       GenerateMessage('Error', 'Failed to extract name and description information from games list...', 2);
  end;

begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  Screen.Cursor:= crHourGlass;
  AddToList:= True;
  case FileExists(FrontendPath+'ini_files\parental_lock.ini') of
    True:
      begin
        ParentalLockGamesList:= THashedStringList.Create;
        ParentalLockGamesList.LoadFromFile(FrontendPath+'ini_files\parental_lock.ini');
        if ParentalLockGamesList.Count > 1 then
           begin
             tempList:= THashedStringList.Create;
             tempList.BeginUpdate;
             for Loop:=1 to ParentalLockGamesList.Count -1 do
                 tempList.Add(DecryptData(ParentalLockGamesList[Loop]));
             tempList.EndUpdate;
             case VerifyMultiSelect of
               True:
                 begin
                   NotAddedGames:= THashedStringList.Create;
                   NotAddedGames.BeginUpdate;
                   GamesToAdd:= THashedStringList.Create;
                   GamesToAdd.BeginUpdate;
                   GamesDescription:= THashedStringList.Create;
                   GamesDescription.BeginUpdate;
                   SelNode:= GamesTreeView.GetFirstSelected;
                   repeat
                     if SelNode <> nil then
                        VerifyGame;
                     SelNode:= GamesTreeView.GetNextSelected(SelNode);
                   until SelNode = nil;
                   NotAddedGames.EndUpdate;
                   GamesToAdd.EndUpdate;
                   GamesDescription.EndUpdate;
                   AddToList:= GamesToAdd.Count > 0;
                   if (NotAddedGames.Count > 0) and (not AddToList) then
                      GenerateMessage('Games Not Added', 'The following games are already in the list:'+#13#10+NotAddedGames.Text, 2);
                 end;
               False:
                 begin
                   if GetGameData(SelectedNode) then
                      begin
                        if tempList.IndexOf(GameInfoData.eName+'='+GetSystemFolderName(GameInfoData.eROMIdentification)) <> -1 then
                           begin
                             GenerateMessage('Game Not Added', 'This game is already in the list!', 2);
                             AddToList:= False;
                           end;
                      end;
                 end;
             end;
           end;
      end;
    False: AddToList:= False;
  end;
  if AddToList then
     begin
       if Assigned(GamesToAdd) then
          begin
            MultiSelectStr:= '';
            if NotAddedGames.Count > 0 then
               MultiSelectStr:= 'Continue ?'+#13#10+#13#10+
                                'The following games are already in the list:'+#13#10+NotAddedGames.Text+#13#10;
            MultiSelectStr:= MultiSelectStr+'Games To Add:'+#13#10;
            for Loop:=0 to GamesToAdd.Count-1 do
                MultiSelectStr:= MultiSelectStr+Format('%s - [%s, %s]', [GamesDescription[Loop], GamesToAdd.Names[Loop], GamesToAdd.ValueFromIndex[Loop]])+#13#10;
            AddToList:= GenerateMessage('Add Games to Parental Lock', MultiSelectStr, 1) = mrYes;
          end;

       Application.ProcessMessages;
       if AddToList then
          begin
            ParentalLockGamesList.BeginUpdate;
            case Assigned(GamesToAdd) of
              True:
                begin
                  for Loop:=0 to GamesToAdd.Count-1 do
                      ParentalLockGamesList.Add(EncryptData(GamesToAdd[Loop]));
                end;
              False: ParentalLockGamesList.Add(EncryptData(GameInfoData.eName+'='+GetSystemFolderName(GameInfoData.eROMIdentification)));
            end;
            ParentalLockGamesList.EndUpdate;
            ParentalLockGamesList.SaveToFile(FrontendPath+'ini_files\parental_lock.ini');
            if MenuParentalLock.Checked then
               begin
                 GameIndex:= GamesTreeView.GetFirstSelected.Index;
                 SetLockedGamesList(False);
                 SetLockedGamesList(True);
                 SetGameType(SelectedFilterName, False);
                 if GamesTreeView.SelectedCount > 1 then
                    GamesTreeView.ClearSelection;
                 if GameIndex >= GamesTreeView.TotalCount then
                    GameIndex:= GamesTreeView.TotalCount-1;
                 SelectNode(GameIndex);
               end;
          end;
     end;
  FreeAndNil(tempList);
  FreeAndNil(ParentalLockGamesList);
  if Assigned(NotAddedGames) then
     FreeAndNil(NotAddedGames);
  if Assigned(GamesToAdd) then
     FreeAndNil(GamesToAdd);
  if Assigned(GamesDescription) then
     FreeAndNil(GamesDescription);
  Screen.Cursor:= crDefault;
end;

procedure TFormMain.PopupPlayGameStandardClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if IsSystemEntry(GameInfoData.eDriverName) then
     Exit;
  case FormPreferences.RunCustomGameSettingsByDefault.Checked of
    True : ExecuteGame(10);
    False: ExecuteGame(TMenuItem(Sender).Tag);
  end;
end;

procedure TFormMain.PopupSetCustomOptionsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eName <> '' then
     SetCustomOptions(GameInfoData.eName, False);
end;

procedure TFormMain.PopupDeleteCustomOptionsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eName <> '' then
     DeleteCustomOptions(GameInfoData.eName);
end;

procedure TFormMain.PopupSetGameDriverCustomOptionsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eDriverName <> '' then
     SetCustomOptions(ChangeFileExt(GameInfoData.eDriverName, ''), Boolean(TMenuItem(Sender).Tag));
end;

procedure TFormMain.PopupDeleteGameDriverCustomOptionsClick(
  Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eDriverName <> '' then
     DeleteCustomOptions(ChangeFileExt(GameInfoData.eDriverName, ''));
end;

procedure TFormMain.PopupSetDebugCustomOptionsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eName <> '' then
     begin
       GetSystemID(GameInfoData.eROMIdentification);
       if SystemID_Number <> 2 then
          SetCustomOptions('debug', True);
     end;
end;

procedure TFormMain.PopupDeleteDebugCustomOptionsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eName <> '' then
     begin
       GetSystemID(GameInfoData.eROMIdentification);
       if SystemID_Number <> 2 then
          DeleteCustomOptions('debug');
     end;
end;

procedure TFormMain.PopupSelectParentGameClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: pGameInfo;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameIsClone(GameInfoData.eClone) then
     begin
       Node:= FindNodeGameName(GameInfoData.eClone, -1);
       if Node.Index = 0 then
          begin
            Data:= GamesTreeView.GetNodeData(Node);
            if CompareText(Data.eName, mClone) <> 0 then
               Exit;
          end;
       GamesTreeView.Selected[Node]:= True;
       GamesTreeView.FocusedNode:= Node;
     end;
end;

procedure TFormMain.PopupRefreshSelectedGameClick(Sender: TObject);
begin
  if not GetGameData(SelectedNode) then
     begin
       GenerateMessage('Error', 'Could not get game info. Aborting...', 2);
       Exit;
     end;
  if not IsSystemEntry(GameInfoData.eDriverName) then
     begin
       GetSystemID(GameInfoData.eROMIdentification);
       CallRefreshGames(3, False, SystemID_Number);
     end;
end;

procedure TFormMain.SetAudit(SysID: ShortInt; AuditID: ShortInt);
begin
  SystemID_Number:= SysID;
  if not Check_ROMsData_File(SysID) then
     Exit;

  if not Assigned(FormAudit) then
     begin
       FormAudit:= TFormAudit.Create(nil);
       LoadAuditIcons;
     end;
  FormAudit.ROMsName:= THashedStringList.Create;
  FormAudit.ROMsSize:= THashedStringList.Create;
  FormAudit.ROMsCRC:= THashedStringList.Create;
  FormAudit.ROMsStatus:= THashedStringList.Create;

  ListROMsName:= THashedStringList.Create;
  ListROMsSize:= THashedStringList.Create;
  ListROMsCRC:= THashedStringList.Create;
  ListROMsNameFullPath:= THashedStringList.Create;
  ParentListROMsName:= THashedStringList.Create;
  ParentListROMsSize:= THashedStringList.Create;
  ParentListROMsCRC:= THashedStringList.Create;
  ParentListROMsNameFullPath:= THashedStringList.Create;
  FormAudit.AuditMode:= AuditID;
  case AuditID of
    1: FormAudit.Caption:= 'Audit All '+GetSystemIniSection(SysID)+ ' Games';
    2: FormAudit.Caption:= 'Audit Available '+GetSystemIniSection(SysID)+ ' Games';
  end;
  FormAudit.Show;
  FormAudit.Refresh;
  FormAudit.Audit;
end;

procedure TFormMain.PopupAuditSelectedGameClick(Sender: TObject);
begin
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not Check_ROMsData_File(SystemID_Number) then
     Exit;

  if not Assigned(FormAudit) then
     begin
       FormAudit:= TFormAudit.Create(nil);
       LoadAuditIcons;
     end;
  FormAudit.ROMsName:= THashedStringList.Create;
  FormAudit.ROMsSize:= THashedStringList.Create;
  FormAudit.ROMsCRC:= THashedStringList.Create;
  FormAudit.ROMsStatus:= THashedStringList.Create;

  ListROMsName:= THashedStringList.Create;
  ListROMsSize:= THashedStringList.Create;
  ListROMsCRC:= THashedStringList.Create;
  ListROMsNameFullPath:= THashedStringList.Create;
  ParentListROMsName:= THashedStringList.Create;
  ParentListROMsSize:= THashedStringList.Create;
  ParentListROMsCRC:= THashedStringList.Create;
  ParentListROMsNameFullPath:= THashedStringList.Create;

  FormAudit.GameName:= GameInfoData.eName;
  FormAudit.ParentGameName:= GameInfoData.eClone;
  FormAudit.GameTitle:= GameInfoData.eDescription;
  FormAudit.LabelGameDescription.Caption:= GameInfoData.eDescription;
  FormAudit.AuditMode:= 0;
  FormAudit.Caption:= 'Audit Game';
  FormAudit.Show;
  FormAudit.Refresh;
  FormAudit.Audit;
end;

procedure TFormMain.PopupAuditDownloadAddressClick(Sender: TObject);
var
  StringURL: String;
begin
  StringURL:= InputBoxEL(FixCaption(PopupAuditDownloadAddress.Caption),
                       'Set internet address for download:', PopupAuditDownloadAddress.Hint);
  if (StringURL <> PopupAuditDownloadAddress.Hint) and (StringURL <> '') then
     PopupAuditDownloadAddress.Hint:= StringURL;
end;

procedure TFormMain.PopupGameDocumentsClick(Sender: TObject);
var
  DatFile: String;
begin
  DatFile:= '';
  if EmulatorFile[1] <> '' then
     begin
       DatFile:= ExtractFilePath(EmulatorFile[1]);
       DatFile:= DatFile+'mameinfo.dat';
     end;
  PopupGameInformation.Enabled:= FileExists(DatFile);
  if not PopupGameInformation.Enabled then
     PopupGameInformation.Enabled:= FileExists(FrontendPath+'ini_files\mameinfo.dat');

  DatFile:= '';
  if EmulatorFile[1] <> '' then
     begin
       DatFile:= ExtractFilePath(EmulatorFile[1]);
       DatFile:= DatFile+'history.dat';
     end;
  PopupGameHistory.Enabled:= FileExists(DatFile);
  if not PopupGameHistory.Enabled then
     PopupGameHistory.Enabled:= FileExists(FrontendPath+'ini_files\history.dat');

  PopupGameDriverInformation.Enabled:= PopupGameInformation.Enabled;
  PopupGameFAQ.Enabled:= FileExists(IncludeTrailingPathDelimiter(FormPreferences.FolderGamesFAQ.Text)+mName+'.faq');

  PopupGameDocsShowAll.Enabled:= PopupGameInformation.Enabled or PopupGameHistory.Enabled or
                                 PopupGameDriverInformation.Enabled or PopupGameFAQ.Enabled;
  PopupGameDocsFeatureNotAvailable.Visible:= not PopupGameDocsShowAll.Enabled;
end;

procedure TFormMain.PopupGameInformationClick(Sender: TObject);
begin
  if (not CheckSelected(GamesTreeView)) or PopupAutomaticGameInformation.Checked then
     Exit;
  ShowGameInfoAll(1);
  //GenerateMessage('Information Not Found', 'There is no information for this game.', 2);
end;

procedure TFormMain.PopupGameHistoryClick(Sender: TObject);
begin
  if (not CheckSelected(GamesTreeView)) or PopupAutomaticGameInformation.Checked then
     Exit;
  ShowGameInfoAll(2);
  //GenerateMessage('History Not Found', 'There is no history for this game.', 2);
end;

procedure TFormMain.PopupGameDriverInformationClick(Sender: TObject);
begin
  if (not CheckSelected(GamesTreeView)) or PopupAutomaticGameInformation.Checked then
     Exit;
  ShowGameInfoAll(3);
  //GenerateMessage('Driver Information Not Found', 'There is no driver information for this game.', 2);
end;

procedure TFormMain.PopupGameFAQClick(Sender: TObject);
begin
  if (not CheckSelected(GamesTreeView)) or PopupAutomaticGameInformation.Checked then
     Exit;
  ShowGameInfoAll(4);
  //GenerateMessage('F.A.Q. Information Not Found', 'There is no F.A.Q. information for this game.', 2);
end;

procedure TFormMain.ShowGameInfoAll(InfoIndex: ShortInt; AutoGameInfo: Boolean = False);
var
  path_mameinfo, path_history, path_faq, path_story: String;

  LineIndex: Integer;
  AddLine: Boolean;
  FoundMAMEInfo, FoundHistory, FoundDriver, FoundFAQShowInfo, FoundStory, ShowInfo: Boolean;
  DATVersion, TempFAQdir: String;
  TextStrings, InfoText: THashedStringList;
  MergedText: TMemoryStream;


  function ReadAutoWindowPosition: Boolean;
  var
    iniFile: TMemIniFile;
  begin
    if Assigned(FormTextViewer) then
       begin
         Result:= FileExists(FrontendPath+'ini_files\el_extras.ini');
         if Result then
            begin
              iniFile:= TMemIniFile.Create(FrontendPath+'ini_files\el_extras.ini');
              Result:= iniFile.SectionExists('GameInfo');
              if Result then
                 begin
                   FormTextViewer.Top:= iniFile.ReadInteger('GameInfo', 'WindowTop', (Screen.Height-460) div 2);
                   FormTextViewer.Left:= iniFile.ReadInteger('GameInfo', 'WindowLeft', (Screen.Width-630) div 2);
                   FormTextViewer.Width:= iniFile.ReadInteger('GameInfo', 'WindowWidth', 626);
                   FormTextViewer.Height:= iniFile.ReadInteger('GameInfo', 'WindowHeight', 443);
                 end;
              FreeAndNil(iniFile);
            end;
       end;
  end;

  function UpdateAutoWindowPosition: Boolean;
  var
    iniFile: TMemIniFile;
  begin
    Result:= Assigned(FormTextViewer);
    if Result then
       begin
         try
           iniFile:= TMemIniFile.Create(FrontendPath+'ini_files\el_extras.ini');
           iniFile.WriteInteger('GameInfo', 'WindowTop', FormTextViewer.Top);
           iniFile.WriteInteger('GameInfo', 'WindowLeft', FormTextViewer.Left);
           iniFile.WriteInteger('GameInfo', 'WindowWidth', FormTextViewer.Width);
           iniFile.WriteInteger('GameInfo', 'WindowHeight', FormTextViewer.Height);
           iniFile.UpdateFile;
         finally
           FreeAndNil(iniFile);
         end;
       end;
  end;

  function InformationData: Boolean;
  begin
    AddLine:= False;
    if Assigned(AutoMAMEInfoDATFile) then
       begin
         LineIndex:= AutoMAMEInfoDATFile.IndexOf('$info='+GameInfoData.eName);
         ShowInfo:= LineIndex > -1;

         if not ShowInfo then
            begin
              if GameIsClone(GameInfoData.eClone) then
                 begin
                   LineIndex:= AutoMAMEInfoDATFile.IndexOf('$info='+GameInfoData.eClone);
                   ShowInfo:= LineIndex > -1;
                 end;
            end;
         if ShowInfo then
            begin
              FoundMAMEInfo:= True;
              Inc(LineIndex);
              InfoText.BeginUpdate;
              InfoText.Clear;
              while Trim(AutoMAMEInfoDATFile[LineIndex]) <> '$end' do
              begin
                case AddLine of
                  False:
                    begin
                      if Trim(AutoMAMEInfoDATFile[LineIndex]) = '$mame' then
                         begin
                           AddLine:= True;
                           InfoText.Add('---------- Information Data ----------'+#13#10);
                         end;
                    end;
                  True: InfoText.Add(AutoMAMEInfoDATFile[LineIndex]);
                end;
                Inc(LineIndex);
              end;
              InfoText.EndUpdate;
              TextStrings.AddStrings(InfoText);
            end;
       end;
  end;

  function HistoryData: Boolean;
  var
    Loop, Loop2: Integer;
  begin
    if Assigned(AutoHistoryDATFile) then
       begin
         AddLine:= False;
         for Loop:=0 to AutoHistoryDATFile.Count -1 do
         begin
           if Copy(AutoHistoryDATFile[Loop], 1, 5) = '$info' then
              begin
                if GetGameHistory(GameInfoData.eName, AutoHistoryDATFile[Loop]) then
                   begin
                     InfoText.BeginUpdate;
                     InfoText.Clear;
                     FoundHistory:= True;
                     Loop2:= Loop+1;
                     InfoText.Add('---------- History Data ----------'+#13#10);
                     while Trim(AutoHistoryDATFile[Loop2]) <> '$end' do
                     begin
                       case AddLine of
                         False:
                           begin
                             if Trim(AutoHistoryDATFile[Loop2]) = '$bio' then
                                AddLine:= True;
                           end;
                         True: InfoText.Add(AutoHistoryDATFile[Loop2]);
                       end;
                       Inc(Loop2);
                     end;
                     InfoText.EndUpdate;
                     TextStrings.AddStrings(InfoText);
                     Break;
                   end;
              end;
         end;
       end;
  end;

  function GameDriverData: Boolean;
  begin
    if Assigned(AutoMAMEInfoDATFile) then
       begin
         AddLine:= False;
         LineIndex:= AutoMAMEInfoDATFile.IndexOf('$info='+GameInfoData.eDriverName);
         if LineIndex > -1 then
            begin
              InfoText.BeginUpdate;
              InfoText.Clear;
              FoundDriver:= True;
              Inc(LineIndex);
              InfoText.Add('---------- Driver Data ----------'+#13#10);
              DATVersion:= AutoMAMEInfoDATFile[0];
              Delete(DATVersion, 1, 2);
              MAMEInfoTextHolder.Lines.Add(DATVersion+#13);
              while Trim(AutoMAMEInfoDATFile[LineIndex]) <> '$end' do
              begin
                case AddLine of
                  False:
                    begin
                      if Trim(AutoMAMEInfoDATFile[LineIndex]) = '$drv' then
                         AddLine:= True;
                    end;
                  True: InfoText.Add(AutoMAMEInfoDATFile[LineIndex]);
                end;
                Inc(LineIndex);
              end;
              InfoText.EndUpdate;
              TextStrings.AddStrings(InfoText);
            end;
       end;
  end;

  function GameFAQData: Boolean;
  begin
    TempFAQdir:= GetZipFolderFull(31);
    ShowInfo:= FileExists(TempFAQdir+GameInfoData.eName+'.faq');

    case ShowInfo of
      True: DATVersion:= TempFAQdir+GameInfoData.eName+'.faq';
      False:
        begin
          if GameIsClone(GameInfoData.eClone) then
              begin
                ShowInfo:= FileExists(TempFAQdir+GameInfoData.eClone+'.faq');
                if ShowInfo then
                   DATVersion:= TempFAQdir+GameInfoData.eClone+'.faq';
              end
          else
              ShowInfo:= False;
        end;
    end;
    if ShowInfo then
       begin
         InfoText.BeginUpdate;
         InfoText.Clear;
         FoundFAQShowInfo:= True;

         InfoText.LoadFromFile(DATVersion);
         InfoText.Insert(0, '---------- Game FAQ Data ----------'+#13#10);
         InfoText.EndUpdate;
         TextStrings.AddStrings(InfoText);
       end;
  end;

  function StoryData: Boolean;
  begin
    if Assigned(AutoStoryDATFile) then
       begin
         AddLine:= False;
         LineIndex:= AutoStoryDATFile.IndexOf('$info='+GameInfoData.eName);
         if LineIndex > -1 then
            begin
              InfoText.BeginUpdate;
              InfoText.Clear;
              FoundStory:= True;
              Inc(LineIndex);
              InfoText.Add('---------- Story Data ----------'+#13#10);
              DATVersion:= AutoStoryDATFile[0];
              Delete(DATVersion, 1, 2);
              MAMEInfoTextHolder.Lines.Add(DATVersion+#13);
              while Trim(AutoStoryDATFile[LineIndex]) <> '$end' do
              begin
                case AddLine of
                  False:
                    begin
                      if (Trim(AutoStoryDATFile[LineIndex]) = '$bio') or
                         (Trim(AutoStoryDATFile[LineIndex]) = '$story') then
                         AddLine:= True;
                    end;
                  True: InfoText.Add(AutoStoryDATFile[LineIndex]);
                end;
                Inc(LineIndex);
              end;
              InfoText.EndUpdate;
              TextStrings.AddStrings(InfoText);
            end;
       end;
  end;

  function CallTextWindow: Boolean;
  begin
    Result:= True;
    if not Assigned(FormTextViewer) then
       FormTextViewer:= TFormTextViewer.Create(nil);
    if FormTextViewer.TextHolder.Font <> MAMEInfoTextHolder.Font then
       FormTextViewer.TextHolder.Font:= MAMEInfoTextHolder.Font;
    if FormTextViewer.TextHolder.Color <> MAMEInfoTextHolder.Color then
       FormTextViewer.TextHolder.Color:= MAMEInfoTextHolder.Color;

    FormTextViewer.LabelGameDescription.Caption:= GameInfoData.eDescription;
    FormTextViewer.UpdateGameIcon;

    FormTextViewer.TextHolder.Lines.BeginUpdate;
    FormTextViewer.TextHolder.Clear;
    try
      FormTextViewer.Position:= poDesigned;
      FormTextViewer.BorderStyle:= bsSizeable;
      case AutoGameInfo of
        True:
          begin
            FormTextViewer.Caption:= FixCaption(PopupAutomaticGameInformation.Caption);
            if FormTextViewer.Tag = 0 then
               begin
                 ReadAutoWindowPosition;
                 FormTextViewer.FormStyle:= fsStayOnTop;
                 FormTextViewer.Tag:= 1;
               end;
            if Assigned(MergedText) then
               FormTextViewer.TextHolder.Lines.LoadFromStream(MergedText);

            FormTextViewer.TextHolder.Lines.EndUpdate;
            FormTextViewer.Show;
          end;
        False:
          begin
            case InfoIndex of
              0: FormTextViewer.Caption:= 'Viewing Complete Game Info';
              1: FormTextViewer.Caption:= 'Viewing Game Information - [mameinfo.dat]';
              2: FormTextViewer.Caption:= 'Viewing Game History - [history.dat]';
              3: FormTextViewer.Caption:= Format('Viewing Game Driver Information [%s] - [mameinfo.dat]',
                                 [GameInfoData.eDriverName]);
              4: FormTextViewer.Caption:= Format('Viewing [%s] - F.A.Q. - Frequently Asked Questions',
                                 [ExtractFileName(DATVersion)]);
              5: FormTextViewer.Caption:= 'Viewing Story Information - [story.dat]';
            end;
            ReadAutoWindowPosition;
            if Assigned(MergedText) then
               FormTextViewer.TextHolder.Lines.LoadFromStream(MergedText);
            FormTextViewer.TextHolder.Lines.EndUpdate;
            FormTextViewer.ShowModal;
          end;
      end;
      FocusGamesList;
    except
      Result:= False;
      if Assigned(MergedText) then
         GenerateMessage('Error', 'Failed to load texts from memory stream to the RichEdit component.', 2);
    end;

  end;

  function GetFileFullPath(FileName: String): String;
  begin
    Result:= '';
    if EmulatorFile[1] <> '' then
       begin
         Result:= ExtractFilePath(EmulatorFile[1]);
         Result:= Result+FileName;
       end;
    if not FileExists(Result) then
       begin
         if FileExists(FrontendPath+'ini_files\'+FileName) then
            Result:= FrontendPath+'ini_files\'+FileName;
       end;
  end;

  procedure LoadText(ComboBoxHolder: TComboBox);
  begin
    case ComboBoxHolder.ItemIndex of
      1: InformationData;
      2: HistoryData;
      3: GameDriverData;
      4: GameFAQData;
      5: StoryData;
    end;
  end;

begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;

  if ((InfoIndex in [0, 1, 3]) or AutoGameInfo) then
      path_mameinfo:= GetFileFullPath('mameinfo.dat');

  if ((InfoIndex in [0, 2]) or AutoGameInfo) then
     path_history:= GetFileFullPath('history.dat');

  if ((InfoIndex in [0, 4]) or AutoGameInfo) and
      (FormPreferences.FolderGamesFAQ.Text <> '') then
     begin
       path_faq:= GetZipFolderFull(31)+GameInfoData.eName+'.faq';
       if not FileExists(path_faq) then
          begin
            if GameIsClone(GameInfoData.eClone) then
               path_faq:= GetZipFolderFull(31)+GameInfoData.eClone+'.faq';
          end;
     end
  else
     path_faq:= '';

  if ((InfoIndex in [0, 5]) or AutoGameInfo) then
     path_story:= GetFileFullPath('story.dat');

  if (path_mameinfo <> '') or (path_history <> '') or (path_faq <> '') or (path_story <> '') then
     begin
       if (FileExists(path_mameinfo)) or (FileExists(path_history)) or
          (FileExists(path_faq)) or (FileExists(path_story)) then
          begin
            if FileExists(path_mameinfo) then
               begin
                 if not Assigned(AutoMAMEInfoDATFile) then
                    begin
                      AutoMAMEInfoDATFile:= THashedStringList.Create;
                      AutoMAMEInfoDATFile.LoadFromFile(path_mameinfo);
                    end;
               end;

            if FileExists(path_history) then
               begin
                 if not Assigned(AutoHistoryDATFile) then
                    begin
                      AutoHistoryDATFile:= THashedStringList.Create;
                      AutoHistoryDATFile.LoadFromFile(path_history);
                    end;
               end;

            if FileExists(path_story) then
               begin
                 if not Assigned(AutoStoryDATFile) then
                    begin
                      AutoStoryDATFile:= THashedStringList.Create;
                      AutoStoryDATFile.LoadFromFile(path_story);
                    end;
               end;

            // ShowAutomaticGameInformation start procedure
            //if AutoGameInfo and FormPreferences.AutomaticGameInformationOpenWindow.Checked then
            //   CallTextWindow; // new function call
            ProcessingAutomaticMAMEInfoDAT:= True;
            FoundMAMEInfo:= False;
            FoundHistory:= False;
            FoundDriver:= False;
            FoundStory:= False;
            AddLine:= False;
            ShowInfo:= False;

            InfoText:= THashedStringList.Create;
            TextStrings:= THashedStringList.Create;
            TextStrings.BeginUpdate;
            case AutoGameInfo of
              True:
                begin
                  LoadText(FormPreferences.AutomaticGameInformation1);
                  LoadText(FormPreferences.AutomaticGameInformation2);
                  LoadText(FormPreferences.AutomaticGameInformation3);
                  LoadText(FormPreferences.AutomaticGameInformation4);
                  LoadText(FormPreferences.AutomaticGameInformation5);
                end;
              False:
                begin
                  if InfoIndex in [0, 1] then
                     InformationData;
                  if InfoIndex in [0, 2] then
                     HistoryData;
                  if InfoIndex in [0, 3] then
                     GameDriverData;
                  if InfoIndex in [0, 4] then
                     GameFAQData;
                  if InfoIndex in [0, 5] then
                     StoryData;
                end;
            end;
            FreeAndNil(InfoText);

            if (not FoundMAMEInfo) and (not FoundHistory) and (not FoundDriver) and
               (not FoundFAQShowInfo) and (not FoundStory) then
               begin
                 case AutoGameInfo of
                   True:
                     begin
                       case FormPreferences.AutomaticGameInformationOpenWindow.Checked of
                         True:
                           begin
                             if Assigned(FormTextViewer) then
                                begin
                                  FormTextViewer.TextHolder.Lines.Clear;
                                  FormTextViewer.LabelGameDescription.Caption:= GameInfoData.eDescription;
                                  FormTextViewer.UpdateGameIcon;
                                end;
                           end;
                         False:
                           begin
                             MAMEInfoTextHolder.Lines.Clear;
                           end;
                       end;
                     end;
                   False:
                     begin
                       FreeAndNil(FormTextViewer);
                     end;
                 end;
               end
            else

            if (FoundMAMEInfo or FoundHistory or FoundDriver or FoundFAQShowInfo or FoundStory) or
               (FoundMAMEInfo and FoundHistory and FoundDriver and FoundFAQShowInfo and FoundStory) then
               begin
                 MergedText:= TMemoryStream.Create;
                 TextStrings.SaveToStream(MergedText);
                 FreeAndNil(TextStrings);
                 MergedText.Seek(0, 0);

                 case AutoGameInfo of
                   True:
                     begin
                       case FormPreferences.AutomaticGameInformationOpenWindow.Checked of
                         True:
                           begin
                             CallTextWindow;
                           end;
                         False:
                           begin
                             MAMEInfoTextHolder.Lines.BeginUpdate;
                             MAMEInfoTextHolder.Lines.Clear;
                             try
                               MAMEInfoTextHolder.Lines.LoadFromStream(MergedText);
                             except
                               GenerateMessage('Error', 'Failed to load texts from memory stream to the RichEdit component.', 2);
                             end;
                             MAMEInfoTextHolder.Lines.EndUpdate;

                             if not PanelGameDocuments.Visible then
                                begin
                                  PanelGameDocuments.Visible:= True;
                                  SplitterMAMEInfo.Visible:= True;
                                end;
                           end;
                       end;
                     end;
                   False:
                     begin
                       CallTextWindow;
                     end;
                 end;
                 MergedText.Free;
               end;
            FreeAndNil(TextStrings);
            ProcessingAutomaticMAMEInfoDAT:= False;
            // ShowAutomaticGameInformation end procedure
          end
       else
          begin
            if AutoGameInfo then
               PopupAutomaticGameInformation.Click;
          end;
     end;
  case AutoGameInfo of
    True:
      begin
        if (not PanelScreenshotsArea.Visible) and
           (not FormPreferences.AutomaticGameInformationOpenWindow.Checked) then
           begin
             PanelScreenshotsArea.Visible:= True;
             Splitter.Visible:= True;
             MenuShowImages.OnClick(Self);
           end;
      end;
    False:
      begin
        FreeAndNil(AutoMAMEInfoDATFile);
        FreeAndNil(AutoHistoryDATFile);
        FreeAndNil(AutoStoryDATFile);
        if Assigned(FormTextViewer) then
           begin
             UpdateAutoWindowPosition;
             FormTextViewer.Close;
             FormTextViewer.Release;
             FormTextViewer:= nil;
           end;
      end;
  end;
end;

procedure TFormMain.PopupAutomaticGameInformationClick(Sender: TObject);

  function UpdateAutoWindowPosition: Boolean;
  var
    iniFile: TMemIniFile;
  begin
    Result:= Assigned(FormTextViewer);
    if Result then
       begin
         try
           iniFile:= TMemIniFile.Create(FrontendPath+'ini_files\el_extras.ini');
           iniFile.WriteInteger('GameInfo', 'WindowTop', FormTextViewer.Top);
           iniFile.WriteInteger('GameInfo', 'WindowLeft', FormTextViewer.Left);
           iniFile.WriteInteger('GameInfo', 'WindowWidth', FormTextViewer.Width);
           iniFile.WriteInteger('GameInfo', 'WindowHeight', FormTextViewer.Height);
           iniFile.UpdateFile;
         finally
           FreeAndNil(iniFile);
         end;
       end;
  end;

begin
  case PopupAutomaticGameInformation.Checked of
    True:
      begin
        ShowGameInfoAll(0, True);
      end;
    False:
      begin
        FreeAndNil(AutoMAMEInfoDATFile);
        FreeAndNil(AutoHistoryDATFile);
        FreeAndNil(AutoStoryDATFile);

        case Assigned(FormTextViewer) of
          True:
            begin
              UpdateAutoWindowPosition;
              FormTextViewer.Close;
              FormTextViewer.Release;
              FormTextViewer:= nil;
            end;
          False:
            begin
              MAMEInfoTextHolder.Lines.BeginUpdate;
              MAMEInfoTextHolder.Lines.Clear;
              MAMEInfoTextHolder.Lines.EndUpdate;
              SplitterMAMEInfo.Visible:= False;
              PanelGameDocuments.Visible:= False;
              if PanelGameDocuments.Align = alClient then
                 begin
                   PanelGameDocuments.Align:= alTop;
                   if PanelGameDocuments.Tag <> 0 then
                      PanelGameDocuments.Height:= PanelGameDocuments.Tag
                   else
                      PanelGameDocuments.Height:= 151;
                 end;
              MenuShowImages.OnClick(Self);
            end;
        end;
      end;
  end;
end;

procedure TFormMain.MenuCreateMAMEGamesListClick(Sender: TObject);
begin
  if (EmulatorFile[TMenuItem(Sender).Tag] = '') or (not FileExists(EmulatorFile[TMenuItem(Sender).Tag])) then
     Exit;
  FormStatus.Show;
  CancelCurrentOperation:= False;
  FormStatus.KeyPreview:= True;
  NoScreenshotLoaded:= False;

  if CreateGamesListXML(TMenuItem(Sender).Tag) then
     begin
       ClearImage;
       Application.ProcessMessages;
       if PopupGamesUseMAMu_Icons.Checked then
          ResetMAMu_ImageList;
       ClearTreeView(GamesTreeView);
       CallRefreshGames(0, True, TMenuItem(Sender).Tag);
       LoadListCPU(FilterCPUList);
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
  FormStatus.KeyPreview:= False;
  FormStatus.Close;
end;

procedure TFormMain.MenuCreateZiNcGamesListClick(Sender: TObject);
begin
  if (EmulatorFile[2] = '') or (not FileExists(EmulatorFile[2])) then
     Exit;

  FormStatus.Show;
  FormStatus.LabelMessage.Caption:= 'Detecting emulator version.';
  FormStatus.LabelMessage.Refresh;
  GetEmulatorVersion(2, EmulatorFile[2], EmulatorVersion[2]);
  CancelCurrentOperation:= False;
  FormStatus.KeyPreview:= True;
  NoScreenshotLoaded:= False;
  //SetCurrentDir(ExtractFilePath(EmulatorFile[2]));

  if CreateGamesListZiNc then
     begin
       ClearImage;
       Application.ProcessMessages;
       if PopupGamesUseMAMu_Icons.Checked then
          ResetMAMu_ImageList;
       ClearTreeView(GamesTreeView);
       CallRefreshGames(0, True, 2);
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
  FormStatus.KeyPreview:= False;
  FormStatus.Close;
end;

procedure TFormMain.GamesTreeViewKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (FormPreferences.HotRodSE.Checked) or (FormPreferences.XArcade.Checked) then
     begin
       if Shift = [ssCtrl] then
          MenuViewFullScreen.Click
       else
       if Key = VK_SPACE then
          KeyBd_Event(VK_PRIOR, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Up" key pressing
       else
       if Key = Ord('X') then
          KeyBd_Event(VK_NEXT, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Down" key pressing
       else
       if (Key = VK_NUMPAD4) and (Shift = [ssCtrl]) then
          KeyBd_Event(VK_LEFT, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Left Key " key pressing
       else
       if (Key = VK_NUMPAD6) and (Shift = [ssCtrl]) then
          KeyBd_Event(VK_RIGHT, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Right Key" key pressing
       else
       if Shift = [ssAlt] then
          KeyBd_Event(VK_HOME, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Home Key" key pressing
       else
       if Key = Ord('Z') then
          KeyBd_Event(VK_END, 0, 0, KEYEVENTF_KEYUP) // Simutate a "End Key" key pressing
       else
       if Key = VK_NUMPAD8 then
          KeyBd_Event(VK_UP, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Up Key" key pressing
       else
       if Key = VK_NUMPAD2 then
          KeyBd_Event(VK_DOWN, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Down Key" key pressing
       else
       if Key = VK_NUMPAD4 then
          GamesTreeView.ScrollBy(-5,0)
       else
       if Key = VK_NUMPAD6 then
          GamesTreeView.ScrollBy(5,0)
       else
       if Key = Ord('C') then
          ButtonRandomGame.Click // Simulate a "Random Game" status bar panel click
       else
       if Key = Ord('E') then
          MenuShowImages.Click // Toggle images ON/OFF
       else
       if ((Key = Ord('6')) and FormPreferences.XArcade.Checked) or
          ((Key = Ord('A')) and FormPreferences.HotRodSE.Checked) then
          PopupAutomaticGameInformation.Click // Simulate auto game info pressing (hotkey F3)
       else
       if Key = Ord('W') then
          PopupGamesUseMAMu_Icons.Click; // Simulate use MAMu_ icons pressing
     end
  else
  if FormPreferences.SlikStik.Checked then
     begin
       if Shift = [ssShift] then
          MenuViewFullScreen.Click
       else
       if Key = Ord('7') then
          KeyBd_Event(VK_PRIOR, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Up" key pressing
       else
       if Key = Ord('0') then
          KeyBd_Event(VK_NEXT, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Down" key pressing
       else
       if Key = Ord('H') then
          KeyBd_Event(VK_HOME, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Home Key" key pressing
       else
       if Key = Ord('Z') then
          KeyBd_Event(VK_END, 0, 0, KEYEVENTF_KEYUP) // Simutate a "End Key" key pressing
       else
       if Key = Ord('9') then
          ButtonRandomGame.Click // Simulate a "Random Game" status bar panel click
       else
       if Key = Ord('6') then
          MenuShowImages.Click // Toggle images ON/OFF
       else
       if Key = Ord('A') then
          PopupAutomaticGameInformation.Click // Simulate auto game info pressing (hotkey F3)
       else
       if Key = Ord('W') then
          PopupGamesUseMAMu_Icons.Click; // Simulate use MAMu_ icons pressing
     end
  else
  if FormPreferences.Devastator2.Checked then
     begin
       if Shift = [ssShift] then
          MenuViewFullScreen.Click
       else
       if Key = Ord('X') then
          KeyBd_Event(VK_PRIOR, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Up" key pressing
       else
       if Key = VK_SPACE then
          KeyBd_Event(VK_NEXT, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Page Down" key pressing
       else
       if Shift = [ssAlt] then
          KeyBd_Event(VK_END, 0, 0, KEYEVENTF_KEYUP) // Simutate a "End Key" key pressing
       else
       if Key = Ord('Z')then
          KeyBd_Event(VK_HOME, 0, 0, KEYEVENTF_KEYUP) // Simutate a "Home Key" key pressing
       else
       if Shift = [ssCtrl] then
          ButtonRandomGame.Click // Simulate a "Random Game" status bar panel click
       else
       if Key = Ord('L') then
          MenuShowImages.Click // Toggle images ON/OFF
       else
       if Key = Ord('4') then
          PopupAutomaticGameInformation.Click // Simulate auto game info pressing (hotkey F3)
       else
       if Key = Ord('A') then
          PopupGamesUseMAMu_Icons.Click; // Simulate use MAMu_ icons pressing
     end;
end;

procedure TFormMain.GamesTreeViewKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if (not FormPreferences.HotRodSE.Checked) and (not FormPreferences.XArcade.Checked) and (not FormPreferences.SlikStik.Checked) and (not FormPreferences.Devastator2.Checked) then
     begin
        if Key = VK_F11 then
           ButtonPreviousImage.OnClick(Self)
        else
        if Key = VK_F12 then
           ButtonNextImage.OnClick(Self)
        else
        if Key = VK_F9 then
           CycleImageType
        else
        if (Key = VK_F7) and (Shift = [ssShift]) then
           begin
             FormPreferences.PlayAudio.Checked:= not FormPreferences.PlayAudio.Checked;
             FormPreferences.PlayMNG.Checked:= not FormPreferences.PlayMNG.Checked;
           end
        else
        if (Key = Ord('T')) and (Shift = [ssCtrl]) then
           ToolBarPanel.Visible:= not ToolBarPanel.Visible
        else
        if (Key = Ord('I')) and (Shift = [ssCtrl]) then
           ImagesToolBarPanel.Visible:= not ImagesToolBarPanel.Visible
        else
        if (Key = VK_F3) and (Shift = [ssCtrl]) then
           ToggleFavoriteLastFilter;
     end
  else

  if (FormPreferences.HotRodSE.Checked) or (FormPreferences.XArcade.Checked) or (FormPreferences.SlikStik.Checked) or (FormPreferences.Devastator2.Checked) then
      begin
        if (Key = VK_NUMPAD2) or (Key = VK_NUMPAD6) or (Key = VK_NUMPAD4) or (Key = VK_NUMPAD8) then
           Exit;

        if Key = Ord('1') then // Player 1 Start button starts game with default options
           PopupPlayGameStandard.Click// OnClick(Self)
        else

        if Key = Ord('R') then
           begin
             case FormPreferences.SlikStikSwap2ndPlayerStick.Checked of
               True : InvertCycleImageType;
               False: CycleImageType; //SlikStik UP/DOWN is inverted, "R" means "DOWN" (old controllers)
             end;
           end
        else

        if Key = Ord('F') then
           begin
             case FormPreferences.SlikStikSwap2ndPlayerStick.Checked of
               True : CycleImageType;
               False: InvertCycleImageType; //SlikStik UP/DOWN is inverted, "F" means "UP" (old controllers)
             end;
           end
        else

        if Key = Ord('D') then
           ButtonPreviousImage.OnClick(Self)
        else

        if Key = Ord('G') then
           ButtonNextImage.OnClick(Self)
        else
           Key:= 0;
      end;
end;

procedure TFormMain.MenuCreateDaphneGamesListClick(Sender: TObject);
begin
  if (EmulatorFile[3] = '') or (not FileExists(EmulatorFile[3])) then
     Exit;
  FormStatus.Show;
  FormStatus.LabelMessage.Caption:= 'Detecting emulator version.';
  FormStatus.LabelMessage.Refresh;
  GetEmulatorVersion(3, EmulatorFile[3], EmulatorVersion[3]);
  CancelCurrentOperation:= False;
  FormStatus.KeyPreview:= True;
  NoScreenshotLoaded:= False;
  
  if CreateGamesListDaphne then
     begin
       ClearImage;
       Application.ProcessMessages;
       if PopupGamesUseMAMu_Icons.Checked then
          ResetMAMu_ImageList;
       ClearTreeView(GamesTreeView);
       CallRefreshGames(0, True, 3);
       Application.ProcessMessages;
     end;
  SetCurrentDir(FrontendPath);
  FormStatus.KeyPreview:= False;
  FormStatus.Close;
end;

procedure TFormMain.ButtonPreviousImageClick(Sender: TObject);
begin
  ButtonViewImage(0);
end;

procedure TFormMain.ButtonNextImageClick(Sender: TObject);
begin
  ButtonViewImage(1);
end;

procedure TFormMain.ButtonNextTypeClick(Sender: TObject);
begin
  CycleImageType;
end;

procedure TFormMain.ButtonPreviousTypeClick(Sender: TObject);
begin
  InvertCycleImageType;
end;

procedure TFormMain.ImagesClick(Sender: TObject);
begin
  ButtonNextType.Click;
end;

procedure TFormMain.MenuToolBarSettingsClick(Sender: TObject);
begin
  if not Assigned(FormToolBarEditor) then
     FormToolBarEditor:= TFormToolBarEditor.Create(nil);
  FormToolBarEditor.ShowModal;
  FreeAndNil(FormToolBarEditor);
end;

procedure TFormMain.MenuImagesToolBarEditorClick(Sender: TObject);
begin
  if not Assigned(FormImagesToolBarEditor) then
     FormImagesToolBarEditor:= TFormImagesToolBarEditor.Create(nil);
  FormImagesToolBarEditor.ShowModal;
  FreeAndNil(FormImagesToolBarEditor);
end;

procedure TFormMain.ToolBarButtonsMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
     MenuToolBarSettings.Click;
end;

procedure TFormMain.ImagesToolbarButtonsMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
     MenuImagesToolBarEditor.Click;
end;

procedure TFormMain.PopupArcadeListAllClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonGameFilterArcade.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       Exit;
     end;

  if ColumnsProfile[TMenuItem(Sender).Tag] <> ColumnsProfile[ButtonGameFilterArcade.Tag] then
     begin
       ButtonGameFilterArcade.Tag:= TMenuItem(Sender).Tag;
       ReadColumnProfile;
     end;

  ButtonGameFilterArcade.Tag:= TMenuItem(Sender).Tag;
  SetGameType(SelectedFilterName, False);
end;

procedure TFormMain.WebButtonExitClick(Sender: TObject);
begin
  ButtonShowMAWSGameInfo.Click;
end;

procedure TFormMain.PopupImageFlipHorizontalClick(Sender: TObject);
begin
  case TMenuItem(Sender).Tag of
    0: Images.Bitmap.FlipHorz();
    1: Images.Bitmap.FlipVert();
    2: Images.Bitmap.Rotate90();
  end;
end;

procedure TFormMain.PopupImageStretchClick(Sender: TObject);
begin
  if MenuShowImages.Checked then
     MenuShowImages.OnClick(Self);
end;

procedure TFormMain.WebBrowserEnter(Sender: TObject);
begin
  FocusGamesList;
end;

procedure TFormMain.MenuGenerateZiNcDriverFileClick(Sender: TObject);
var
  Loop: Integer;
  IndexMAME: Integer;
  zinc_list, mame_list, driver_l:THashedStringList;
  zName, zClone, zDriverName, TempString: String;
begin
  if GenerateMessage('Warning', 'A working MAME games list and a working ZiNc games list '+
                     'are required to generate "'+FrontendPath+'ini_files\zinc.ini". Use this only if you need to '+
                     're-create that file.'+
                     #13#10+'Continue ?', 1) = mrNo then
     Exit;

  mame_list:= THashedStringList.Create;
  GetGamesList(mame_list, 1);
  if mame_list.Count = 0 then
     begin
       GenerateMessage('Error', 'MAME games list is empty!. Aborting...', 2);
       FreeAndNil(mame_list);
       Exit;
     end;

  zinc_list:= THashedStringList.Create;
  GetGamesList(zinc_list, 2);
  if zinc_list.Count = 0 then
     begin
       GenerateMessage('Error', 'ZiNc games list is empty!. Aborting...', 2);
       FreeAndNil(zinc_list);
       Exit;
     end;

  with FormStatus do
  begin
    Show;
    LabelStatusType.Caption:= 'Scan Driver Names';
    LabelMessage.Caption:= 'Extracting driver names from MAME.';
    ProgressBar.MaxValue:= zinc_list.Count-1;
    ProgressBar.Progress:= 0;
    Refresh;
  end;
  driver_l:= THashedStringList.Create;
  driver_l.BeginUpdate;
  for Loop:=3 to zinc_list.Count-1 do
  begin
    TempString:= zinc_list[Loop];
    if (TempString <> '') and (TempString[1] <> '[') then
       begin
         GetROMFields(zinc_list, Loop);
         zName:= mName;
         zClone:= mClone;
         zDriverName:= '';
         IndexMAME:= mame_list.IndexOfName(zName);
         if IndexMAME <> -1 then
            begin
              GetROMFields(mame_list, Loop);
              zDriverName:= ChangeFileExt(mDriverName, '');
            end;
         driver_l.Add(zName+'='+zDriverName);
         FormStatus.ProgressBar.Progress:= Loop;
       end;
  end;
  driver_l.Sort;
  driver_l.EndUpdate;
  FreeAndNil(mame_list);
  FreeAndNil(zinc_list);
  FormStatus.Close;
  GenerateMessage('Operation Complete', 'File "'+FrontendPath+'ini_files\zinc.ini" created. '+
                  IntToStr(driver_l.Count)+' games scanned!', 2);

  driver_l.Insert(0, '; drivers list based on "'+EmulatorVersion[2]+'"');
  driver_l.SaveToFile(FrontendPath+'ini_files\zinc.ini');
  FreeAndNil(driver_l);
end;

procedure TFormMain.MenuViewEmulatorsVersionsClick(Sender: TObject);
var
  vString: String;

  procedure GetVersion(emuSystem: ShortInt);
  begin
    if EmulatorVersion[emuSystem] <> '' then
       begin
         if vString <> '' then
            vString:= vString+#13#10;
         vString:= vString+GetSystemIniSection(emuSystem)+#13#10+' -> '+
                   EmulatorVersion[emuSystem];
       end;
  end;

begin
  GetVersion(1);
  GetVersion(2);
  GetVersion(3);
  GetVersion(4);
  GetVersion(5);
  GetVersion(6);
  if vString <> '' then
     GenerateMessage('Emulators Version Information', vString, 2);
end;

procedure TFormMain.MenuExportAllFilesFullFormatClick(Sender: TObject);
var
  ExportGames: THashedStringList;
  Node: PVirtualNode;
  Data: pGameInfo;
begin
  if not CheckTotal(GamesTreeView) then
     Exit;
  ExportGames:= THashedStringList.Create;
  ExportGames.BeginUpdate;

  Node:= GamesTreeView.GetFirst;
  repeat
    Data:= GamesTreeView.GetNodeData(Node);
    case TMenuItem(Sender).Tag of
      0:
        begin
          // all games (full format)
          ExportGames.Add(Format('%s, %s [%s]', [GetSystemFolderName(Data.eROMIdentification),
                                 Data.eDescription, Data.eName]));
        end;
      1:
        begin
          // visible games only (full format)
          if GamesTreeView.IsVisible[Node] then
             ExportGames.Add(Format('%s, %s [%s]', [GetSystemFolderName(Data.eROMIdentification),
                                    Data.eDescription, Data.eName]));
        end;
      2:
        begin
          // all games (gamename=system format)
          ExportGames.Add(Format('%s=%s', [Data.eName,
                                 GetSystemFolderName(Data.eROMIdentification)]));
        end;
      3:
        begin
          // visible games only (gamename=system format)
          if GamesTreeView.IsVisible[Node] then
             ExportGames.Add(Format('%s=%s', [Data.eName,
                                    GetSystemFolderName(Data.eROMIdentification)]));
        end;
    end;
    Node:= GamesTreeView.GetNext(Node);
  until Node = nil;

  ExportGames.Sort;
  ExportGames.EndUpdate;
  if ExportGames.Count > 0 then
     begin
       GamesListSaveDialog.FilterIndex:= 3;
       if GamesListSaveDialog.Execute then
          begin
            if LowerCase(ExtractFileExt(GamesListSaveDialog.FileName)) <> '.txt' then
               GamesListSaveDialog.FileName:= GamesListSaveDialog.FileName+'.txt';
            ExportGames.SaveToFile(GamesListSaveDialog.FileName);
          end;
       GamesListSaveDialog.FilterIndex:= 1;
     end;
  FreeAndNil(ExportGames);
end;

procedure TFormMain.PopupAuditAllGamesMAMEClick(Sender: TObject);
begin
  SetAudit(1, TMenuItem(Sender).Tag);
end;

procedure TFormMain.PopupAuditAllGamesAGEMAMEClick(Sender: TObject);
begin
  SetAudit(4, TMenuItem(Sender).Tag);
end;

procedure TFormMain.PopupAuditAllGamesPinMAMEClick(Sender: TObject);
begin
  SetAudit(5, TMenuItem(Sender).Tag);
end;

procedure TFormMain.MenuImageSettingsClick(Sender: TObject);
begin
  if Assigned(FormPreferences) then
     begin
       FormPreferences.Show;
       FormPreferences.PageControlPreferences.ActivePageIndex:= 2;
       FormPreferences.PageControlFoldersFiles.ActivePageIndex:= 1;
     end;
end;

procedure TFormMain.MenuMAMELoadSaveStateClick(Sender: TObject);
var
  Loop: Integer;

  procedure LoadSaveStateFolders(SystemID: Integer);
  var
    MAMEIniFile: THashedStringList;
    TextLine, ExecutableString, IniFile: String;
    Loop2: Integer;
  begin
    ExecutableString:= EmulatorFile[SystemID];
    if (not FileExists(ExecutableString)) or (ExecutableString = '') then
       Exit;

    iniFile:= GetMAMEIniFileName(ExecutableString, SystemID);
    if not FileExists(iniFile) then
       Exit;

    MAMEIniFile:= THashedStringList.Create;
    MAMEIniFile.LoadFromFile(iniFile);
    for Loop2:=0 to MAMEIniFile.Count -1 do
    begin
      TextLine:= MAMEIniFile[Loop2];
      if Copy(TextLine, 1, 16) = 'state_directory ' then
         begin
           SaveStateDir[SystemID]:= ExtractMAMEIniValue(TextLine);
           Break;
         end;
    end;
    FreeAndNil(MAMEIniFile);

     // MAME only
     if SaveStateDir[SystemID] = '' then
        begin
          if SystemID in [1, 4, 5, 6] then
             SaveStateDir[SystemID]:= ExtractFilePath(EmulatorFile[SystemID])+'sta';
        end
     else
        begin
          if Pos(':', SaveStateDir[SystemID]) = 0 then
             begin
               if SystemID in [1, 4, 5, 6] then
                 SaveStateDir[SystemID]:= ExtractFilePath(EmulatorFile[SystemID])+SaveStateDir[SystemID];
             end;
        end;
  end;

begin
  case MenuMAMELoadSaveState.Checked of
    True:
      begin
        try
          for Loop:= 1 to MaxArcadeSystems do
              SaveStateDir[Loop]:= '';
          LoadSaveStateFolders(1); // MAME
          LoadSaveStateFolders(4); // AGEMAME
          LoadSaveStateFolders(5); // PinMAME
          LoadSaveStateFolders(6); // HazeMD
        except
          GenerateMessage('Error', 'Could not load data into memory variables for save state directories.'+#13#10+
                          'Feature not available. Try restarting the frontend.', 2);
          MenuMAMELoadSaveState.Click;//Checked:= False;
          Exit;
        end;
      end;
    False:
      begin
        for Loop:= 1 to MaxArcadeSystems do
            Finalize(SaveStateDir);
      end;
  end;
end;

function TFormMain.GetSaveStateFileName: String;
var
  Loop: Integer;
  List_sta: THashedStringList;
  SaveStateIni: TMemIniFile;
  time_dateResult: String;
begin
  Result:= '';
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  List_sta:= THashedStringList.Create;
  GetFilesList(SaveStateDir[SystemID_Number], '.sta', GameInfoData.eName+'*.sta', List_sta, False, True, True);
  if List_sta.Count > 0 then
     begin
       if not Assigned(FormLoadSaveState) then
          FormLoadSaveState:= TFormLoadSaveState.Create(nil);
       FormLoadSaveState.SaveStatesFolder.Text:= SaveStateDir[SystemID_Number];
       FormLoadSaveState.SaveStateSlots.Items.BeginUpdate;
       for Loop:= 0 to List_sta.Count-1 do
       begin
         with FormLoadSaveState.SaveStateSlots.Items.Add do
         begin
           ImageIndex:= 64;
           Caption:= ExtractFileName(List_sta[Loop]);
           time_dateResult:= '';
           DateTimeToString(time_dateResult, 'mmm/dd/yyyy - hh:nn:ss AM/PM',
                            FileDateToDateTime(FileAge(List_sta[Loop])));
           SubItems.Add(time_dateResult);
           SubItems.Add(List_sta[Loop]);
         end;
       end;
       FormLoadSaveState.SaveStateSlots.Items.EndUpdate;
       if FileExists(FrontendPath+'ini_files\savestate.ini') then
          begin
            SaveStateIni:= TMemIniFile.Create(FrontendPath+'ini_files\savestate.ini');
            time_dateResult:= GetSystemIniSection(SystemID_Number);
            case SaveStateIni.ValueExists(time_dateResult, GameInfoData.eName) of
              True : FormLoadSaveState.LabelSaveNotSupported.Visible:= not
                       Boolean(SaveStateIni.ReadInteger(GetSystemIniSection(SystemID_Number), GameInfoData.eName, 0));
              False: FormLoadSaveState.LabelSaveNotSupported.Caption:= 'Save state info not found! '+#13#10+
                       'Section ['+time_dateResult+'] -> '+GameInfoData.eName+'.';
            end;
            FreeAndNil(SaveStateIni);
          end;
       FormLoadSaveState.ShowModal;
       if (FormLoadSaveState.MsgResult = mrOk) and
          (FormLoadSaveState.SaveStateSlots.Selected <> nil) then
          begin
            Result:= FormLoadSaveState.SaveStateSlots.Selected.Caption;
            if Result <> '' then
               begin
                 Result:= LongToShortPath(IncludeTrailingPathDelimiter(FormLoadSaveState.SaveStatesFolder.Text)+Result);
                 Result:= ExtractFileName(Result);
               end;
          end;
       FreeAndNil(FormLoadSaveState);
     end
  else
     GenerateMessage('Information', 'No save states were found for "'+
                     mDescription+'"!.', 2);
  FreeAndNil(List_sta);
end;

procedure TFormMain.MenuBiosSetSettingsClick(Sender: TObject);
begin
  if not Assigned(FormBiosSet) then
     FormBiosSet:= TFormBiosSet.Create(nil);
  FormBiosSet.ShowModal;
  FreeAndNil(FormBiosSet);
  if FormPreferences.BiosSetWarning.Checked then
     GenerateMessage('Attention', 'Remember to enable this feature by selecting the "User Defined" '+
                     'menu option in "Advanced Users / Bios Sets" main menu)!', 2);
end;

procedure TFormMain.MenuSetFoldersAudioMNGClick(Sender: TObject);
begin
  FormPreferences.PageControlPreferences.ActivePage:= FormPreferences.TabSheetFoldersZipFiles;
  FormPreferences.PageControlFoldersFiles.ActivePage:= FormPreferences.TabSheetFoldersGeneral;
  FormPreferences.Show;
end;

procedure TFormMain.ArcadeLayoutDevastator2Click(Sender: TObject);

  procedure LoadArcadeImage(ImageFile: String);
  begin
    if FileExists(FormMain.FrontendPath+'resources\images\'+ImageFile) then
       begin
         if not Assigned(FormControllerKeysLayout) then
            FormControllerKeysLayout:= TFormControllerKeysLayout.Create(nil);
         try
           FormControllerKeysLayout.ControllerImage.Picture.LoadFromFile(FormMain.FrontendPath+'resources\images\'+ImageFile);
           FormControllerKeysLayout.ShowModal;
         except
           FormControllerKeysLayout.ControllerImage.Picture:= nil;
         end;
         FreeAndNil(FormControllerKeysLayout);
       end;
  end;

begin
  case TMenuItem(Sender).Tag of
    0: LoadArcadeImage('DevastatorII.jpg');
    1: LoadArcadeImage('HotRodSE.jpg');
    2: LoadArcadeImage('SlikStik.jpg');
    3: LoadArcadeImage('X-Arcade.jpg');
  end;
end;

procedure TFormMain.ButtonGameFilterMainClick(Sender: TObject);
begin
  if not Assigned(FormArcadeGamesFilter) then
     FormArcadeGamesFilter:= TFormArcadeGamesFilter.Create(nil);
  FormArcadeGamesFilter.ShowModal;
  if (FormArcadeGamesFilter.LabelSelectedNode.Caption <> SelectedFilterName) and
     (FormArcadeGamesFilter.LabelSelectedNode.Caption <> 'cancel') then
     begin
       SelectedFilterName:= FormArcadeGamesFilter.LabelSelectedNode.Caption;
       FreeAndNil(FormArcadeGamesFilter);
       SetGameType(SelectedFilterName, False);
     end
  else
     FreeAndNil(FormArcadeGamesFilter);
end;

procedure TFormMain.MenuSmallToolBarClick(Sender: TObject);
var
  tempString: String;

  procedure ResizeImgLst(ImgListName: TImageList; Small: Boolean);
  begin
    case Small of
      True:
        begin
          ImgListName.Width:= 32;
          ImgListName.Height:= 32;
        end;
      False:
        begin
          ImgListName.Width:= 48;
          ImgListName.Height:= 48;
        end;
    end;
  end;

begin
  ToolBarButtons.AutoSize:= True;
  ResizeImgLst(IL_ViewMode_Large, MenuSmallToolBar.Checked);
  ResizeImgLst(IL_ArcadeFilter_Large, MenuSmallToolBar.Checked);
  //ResizeImgLst(IL_ArcadeFilterMain_Large, MenuLargeToolBar.Checked);
  ResizeImgLst(IL_FilterMasterClone_Large, MenuSmallToolBar.Checked);
  ResizeImgLst(IL_FilterHaveMiss_Large, MenuSmallToolBar.Checked);
  ResizeImgLst(IL_FilterWorkingNonWorking_Large, MenuSmallToolBar.Checked);
  ResizeImgLst(IL_FilterNumberScreens_Large, MenuSmallToolBar.Checked);
  ResizeImgLst(IL_ToolBarButtons, MenuSmallToolBar.Checked);

  if MenuSmallToolBar.Checked then
     begin
        ToolBarButtons.ButtonWidth:= 39;
        ToolBarButtons.ButtonHeight:= 38;
      end;
  ToolBarButtons.AutoSize:= False;
  ToolBarButtons.Height:= ToolBarButtons.Height+1;

  if GamesTreeView.Tag = 1 then
     begin
       // execute these lines only if not initializing...
       LoadMainScreenIcons(True);
       tempString:= GetZipFolderFull(32);
       SetIcon(IL_ViewMode_Large, IL_ToolBarButtons, ButtonViewMode.Tag, 0);
       SetIcon(IL_ArcadeFilter_Large, IL_ToolBarButtons, ButtonGameFilterArcade.Tag, 1);
       SetToolBarIcon(SelectedFilterName, tempString+'arcade_filters\', IL_ToolBarButtons, 2);
       SetIcon(IL_FilterMasterClone_Large, IL_ToolBarButtons, ButtonGameFilterMasterClone.Tag, 3);
       SetIcon(IL_FilterHaveMiss_Large, IL_ToolBarButtons, ButtonGameFilterHaveMiss.Tag, 4);
       SetIcon(IL_FilterWorkingNonWorking_Large, IL_ToolBarButtons, ButtonGameFilterWorkingNonWorking.Tag, 5);
       SetIcon(IL_FilterNumberScreens_Large, IL_ToolBarButtons, ButtonGameFilterNumberScreens.Tag, 7);

       if ImageTypeArray[ButtonImagesViewMode.Tag, 1] = '' then
          GenerateMessage('Error', 'Could not set image filename to update the image '+
                          'icon in tool bar buttons.', 2)
       else
          SetToolBarIcon(ImageTypeArray[ButtonImagesViewMode.Tag, 1], GetZipFolderFull(32), IL_ToolBarButtons, 8);
     end;
end;

procedure TFormMain.MenuImagesScanNotUsedImagesClick(Sender: TObject);
begin
  if not Assigned(FormNotUsed) then
     FormNotUsed:= TFormNotUsed.Create(nil);
  FormNotUsed.LabelFeatureDescription.Caption:= 'Select a system, then select '+
          'an image type. Click on button "Scan". Check all items you want to delete, if files '+
          'were found, and click on button "Delete". The files listed do not belong to any game in '+
          'your games list. They can all be excluded.';
  FormNotUsed.ShowModal;
  FreeAndNil(FormNotUsed);
end;

procedure TFormMain.ScanMissingImages(sysID: Integer; AddTitle: Boolean = False; CloseHTML: Boolean = False);
type
  TGameInfoArray = array of TGameInfo;
var
  Loop: Integer;
  Folder, ZipFile: String;
  SearchIcon, IsCloneGame, UseZIPFile, IconIsFound, grayBkColor, HeaderAdded: Boolean;
  el_GamesList: THashedStringList;
  img_GamesList: TGameInfoArray;
  MissingGamesCount, SystemGamesCount: Integer;
  ELFormat, NewFormat: String;
begin
  el_GamesList:= THashedStringList.Create;
  if FormMissingImages.SettingsList.Items[3].Checked and (sysID = 1) then
     GetGamesList(el_GamesList, 1); // MAME
  if FormMissingImages.SettingsList.Items[4].Checked and (sysID = 2) then
     GetGamesList(el_GamesList, 2); // ZiNc
  if FormMissingImages.SettingsList.Items[5].Checked and (sysID = 3) then
     GetGamesList(el_GamesList, 3); // Daphne
  if FormMissingImages.SettingsList.Items[6].Checked and (sysID = 4) then
     GetGamesList(el_GamesList, 4); // AGEMAME
  if FormMissingImages.SettingsList.Items[7].Checked and (sysID = 5) then
     GetGamesList(el_GamesList, 5); // PinMAME
  if FormMissingImages.SettingsList.Items[8].Checked and (sysID = 6) then
     GetGamesList(el_GamesList, 6); // HazeMD

  Application.ProcessMessages;
  FormStatus.Show;
  FormStatus.LabelStatusType.Caption:= Format('%s - [%s - %s]',
      [FixCaption(MenuImagesScanForMissingImages.Caption),
       FormMissingImages.ImageTypeSelector.ItemsEx[FormMissingImages.ImageTypeSelector.ItemIndex].Caption,
       GetSystemIniSection(sysID)]);
  FormStatus.LabelMessage.Caption:= 'Parsing files.';
  FormStatus.ProgressBar.Progress:= 0;
  FormStatus.Refresh;
  MissingGamesCount:= 0;
  SystemGamesCount:= 0;
  Screen.Cursor:= crHourGlass;

  case FormMissingImages.SettingsList.Items[1].Checked of
    True : Folder:= GetZipFolderFull(FormMissingImages.ImageTypeSelector.Tag, sysID); // [imgType, sysID]
    False: Folder:= '';
  end;
  UseZIPFile:= FormMissingImages.SettingsList.Items[2].Checked;
  case UseZIPFile of
    True:
      begin
        ZipFile:= VerifyZipType(imgFolderZipFile[sysID, FormMissingImages.ImageTypeSelector.Tag], False);
        if LowerCase(ExtractFileName(ZipFile)) = 'dummy.zip' then
           ZipFile:= '';
        UseZIPFile:= FileExists(Folder+ZipFile);
        if UseZIPFile then
           begin
             ListROMsName:= THashedStringList.Create;
             ListROMsNameFullPath:= THashedStringList.Create;
             UseZIPFile:= GetContents(Folder+ZipFile, True, False);
           end;
      end;
    False: ZipFile:= '';
  end;
  // sort list and group games by system
  FormStatus.LabelMessage.Caption:= 'Sorting games.';
  FormStatus.Refresh;
  SetLength(img_GamesList, el_GamesList.Count);
  FormStatus.ProgressBar.Progress:= el_GamesList.Count-1;
  grayBkColor:= False;
  for Loop:=0 to el_GamesList.Count-1 do
  begin
    ClearMemoryColumnsVariables;
    GetROMFields(el_GamesList, Loop);
    with img_GamesList[Loop] do
    begin
      eROMIdentification:= mROMIdentification;
      eDescription:= mDescription;
      eName:= mName;
      eClone:= mClone;
    end;
    FormStatus.ProgressBar.Progress:= Loop;
  end;
  FormStatus.LabelMessage.Caption:= 'Searching files.';
  FormStatus.Refresh;
  HeaderAdded:= False;
  if not Assigned(FormMissingImages.MissingImagesList) then
     FormMissingImages.MissingImagesList:= THashedStringList.Create;
  if AddTitle then
     FormMissingImages.MissingImagesList.Insert(0, '<p align="center"><font face="Segoe UI" color="#FF0000" size="3"><b>Missing '+
          FormMissingImages.ImageTypeSelector.ItemsEx[FormMissingImages.ImageTypeSelector.ItemIndex].Caption+
          '</b></font></p>');
  FormStatus.ProgressBar.Progress:= Length(img_GamesList)-1;
  for Loop:=0 to Length(img_GamesList)-1 do
  begin
    GetSystemID(img_GamesList[Loop].eROMIdentification);
    IsCloneGame:= GameIsClone(img_GamesList[Loop].eClone);
    case IsCloneGame of
      True : SearchIcon:= FormMissingImages.SettingsList.Items[0].Checked;
      False: SearchIcon:= True;
    end;
    if SearchIcon then
       begin
         Inc(SystemGamesCount);
         IconIsFound:= False;

         ELFormat:=  GetImageName(img_GamesList[Loop].eName, 1, 0);
         NewFormat:= GetImageName(img_GamesList[Loop].eName, 1, 1);
         if FormMissingImages.SettingsList.Items[1].Checked then
            begin
              // EL format
              IconIsFound:= FileExists(Folder+ELFormat+'.png'); // search unzipped image
              if (not IconIsFound) and (not FormMissingImages.ImageTypeSelector.Tag in [0, 1, 7, 8]) then
                 begin
                   IconIsFound:= FileExists(Folder+ELFormat+'.jpg');
                   if not IconIsFound then
                      IconIsFound:= FileExists(Folder+ELFormat+'.gif');
                 end;
              // MAME new format
              if not IconIsFound then
                 begin
                   IconIsFound:= FileExists(Folder+NewFormat+'.png'); // search unzipped image
                   if (not IconIsFound) and (not FormMissingImages.ImageTypeSelector.Tag in [0, 1, 7, 8]) then
                      begin
                        IconIsFound:= FileExists(Folder+NewFormat+'.jpg');
                        if not IconIsFound then
                           IconIsFound:= FileExists(Folder+NewFormat+'.gif');
                      end;
                 end;

            end;

         if (FormMissingImages.SettingsList.Items[2].Checked) and UseZIPFile and (not IconIsFound) then
            begin
              // EL format
              IconIsFound:= ListROMsNameFullPath.IndexOf(ELFormat+'.png') <> -1;
              if (not IconIsFound) and (not FormMissingImages.ImageTypeSelector.Tag in [0, 1, 7, 8]) then
                 begin
                   IconIsFound:= ListROMsNameFullPath.IndexOf(ELFormat+'.jpg') <> -1;
                   if not IconIsFound then
                      IconIsFound:= ListROMsNameFullPath.IndexOf(ELFormat+'.gif') <> -1;
                 end;
              // MAME new format
              if not IconIsFound then
                 begin
                   IconIsFound:= ListROMsNameFullPath.IndexOf(NewFormat+'.png') <> -1;
                   if (not IconIsFound) and (not FormMissingImages.ImageTypeSelector.Tag in [0, 1, 7, 8]) then
                      begin
                        IconIsFound:= ListROMsNameFullPath.IndexOf(NewFormat+'.jpg') <> -1;
                        if not IconIsFound then
                           IconIsFound:= ListROMsNameFullPath.IndexOf(NewFormat+'.gif') <> -1;
                      end;
                 end;
            end;

         if not (IconIsFound) then
            begin
              if not HeaderAdded then
                 begin
                   FormMissingImages.MissingImagesList.Add('<table border="0" cellspacing="0" width="800" style="border-collapse: collapse">');
                   FormMissingImages.MissingImagesList.Add('  <tr>');
                   FormMissingImages.MissingImagesList.Add('    <td width="800" colspan="3"><i><font face="Segoe UI" color="#FF0000"><b>'+GetEmuFullDescription(sysID)+'</b></font></i></td>');
                   FormMissingImages.MissingImagesList.Add('  </tr>');
                   FormMissingImages.MissingImagesList.Add('  <tr>');
                   case FormMissingImages.SettingsList.Items[0].Checked of
                     True : FormMissingImages.MissingImagesList.Add('    <td width="450" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Description</b></td>');
                     False: FormMissingImages.MissingImagesList.Add('    <td width="625" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Description</b></td>');
                   end;
                   FormMissingImages.MissingImagesList.Add('    <td width="175" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Game Name</b></td>');
                   if FormMissingImages.SettingsList.Items[0].Checked then
                      FormMissingImages.MissingImagesList.Add('    <td width="175" bgcolor="#000000"><font face="Segoe UI" color="#FFFFFF"><b>Clone of</b></td>');
                   FormMissingImages.MissingImagesList.Add('  </tr>');
                   HeaderAdded:= True;
                 end;
              Inc(MissingGamesCount);
              FormMissingImages.MissingImagesList.Add('  <tr>');
              case grayBkColor of
                True:
                  begin
                    FormMissingImages.MissingImagesList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+img_GamesList[Loop].eDescription+'</td>');
                    FormMissingImages.MissingImagesList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+img_GamesList[Loop].eName+'</td>');
                  end;
                False:
                  begin
                    FormMissingImages.MissingImagesList.Add('    <td><font face="Segoe UI">'+img_GamesList[Loop].eDescription+'</td>');
                    FormMissingImages.MissingImagesList.Add('    <td><font face="Segoe UI">'+img_GamesList[Loop].eName+'</td>');
                  end;
              end;
              if FormMissingImages.SettingsList.Items[0].Checked then
                 begin
                   case grayBkColor of
                     True : FormMissingImages.MissingImagesList.Add('    <td bgcolor="#D4D0C8"><font face="Segoe UI">'+img_GamesList[Loop].eClone+'</td>');
                     False: FormMissingImages.MissingImagesList.Add('    <td><font face="Segoe UI">'+img_GamesList[Loop].eClone+'</td>');
                   end;
                 end;
              FormMissingImages.MissingImagesList.Add('  </tr>');
              grayBkColor:= not grayBkColor;
            end;
       end;
    FormStatus.ProgressBar.Progress:= Loop;
  end;
  if SystemGamesCount > 0 then
     begin
        FormMissingImages.MissingImagesList.Add('  <tr>');
        FormMissingImages.MissingImagesList.Add('    <td width="800" colspan="3" bgcolor="#3399FF"><font face="Segoe UI">'+
                        '<b>&nbsp;&nbsp;&nbsp;&nbsp;Games Scanned: '+IntToStr(SystemGamesCount)+'<br>'+
                        '&nbsp;&nbsp;&nbsp;&nbsp;Missing Images: '+IntToStr(MissingGamesCount)+'</br>'+
                        '&nbsp;&nbsp;&nbsp;&nbsp;Search Path: '+Folder+'</br>');
        if UseZIPFile then
           FormMissingImages.MissingImagesList.Add('&nbsp;&nbsp;&nbsp;&nbsp;Zip File: '+Folder+ZipFile+'</br>');
        FormMissingImages.MissingImagesList.Add('</td>');
        FormMissingImages.MissingImagesList.Add('  </tr>');
     end;
  FormMissingImages.MissingImagesList.Add('</table><p>');
  FreeAndNil(ListROMsName);
  FreeAndNil(ListROMsNameFullPath);
  for Loop:=Length(img_GamesList)-1 downto 0 do
      Finalize(img_GamesList[Loop]);

  Screen.Cursor:= crDefault;
  if CloseHTML then
     begin
       FormMissingImages.MissingImagesList.Add('</table><p>');
       FormMissingImages.MissingImagesList.Add('</b><font color="#008000">Generated by Emu Loader v'+
                       GetFileInfo(Application.ExeName, VersionInfo[3])+'<br>Date: '+
                       DateToStr(Date)+' - Time: '+TimeToStr(Time)+'</font></font></p>');
       FormStatus.Close;
       if GamesListSaveDialog.Execute then
          FormMissingImages.MissingImagesList.SaveToFile(GamesListSaveDialog.Filename);
       FreeAndNil(FormMissingImages.MissingImagesList);
     end;
  FreeAndNil(el_GamesList);
end;

procedure TFormMain.UpdateImageTypeDescriptionComboBoxEx(ComboBoxExHolder: TComboBoxEx);

  function CheckImageType(EditHolder: TEdit; TypeIndex: ShortInt): Boolean;
  begin
    if EditHolder.Text <> ImageTypeArray[TypeIndex, 0] then
       ComboBoxExHolder.ItemsEx[TypeIndex].Caption:= EditHolder.Text;
  end;

begin
  ComboBoxExHolder.ItemsEx.BeginUpdate;
  CheckImageType(FormPreferences.DescriptionTitleSnapshots, 0);
  CheckImageType(FormPreferences.DescriptionMarquees, 2);
  CheckImageType(FormPreferences.DescriptionFlyers, 3);
  CheckImageType(FormPreferences.DescriptionCabinets, 4);
  CheckImageType(FormPreferences.DescriptionControlPanels, 5);
  CheckImageType(FormPreferences.DescriptionControlPanelLayouts, 6);
  CheckImageType(FormPreferences.DescriptionSelect, 7);
  CheckImageType(FormPreferences.DescriptionVersus, 8);
  CheckImageType(FormPreferences.DescriptionWallpapers, 9);
  CheckImageType(FormPreferences.DescriptionHardware, 10);
  CheckImageType(FormPreferences.DescriptionCustomImage, 11);
  ComboBoxExHolder.ItemsEx.EndUpdate;
end;

procedure TFormMain.MenuImagesScanForMissingImagesClick(Sender: TObject);
begin
  if not CheckTotal(GamesTreeView) then
     Exit;

  if not Assigned(FormMissingImages) then
     FormMissingImages:= TFormMissingImages.Create(nil);
  LoadMAMu_SettingsIcons(FormMissingImages.IL_Settings);
  FormMissingImages.ShowModal;
  FreeAndNil(FormMissingImages);
end;

procedure TFormMain.PopupGameDocsShowAllClick(Sender: TObject);
begin
  if not PopupGameDocsShowAll.Enabled then
     Exit;
  case PopupAutomaticGameInformation.Checked of
    True : Exit;
    False: ShowGameInfoAll(0);
  end;
end;

procedure TFormMain.MenuViewGamesListVersionsClick(Sender: TObject);
var
  msgString: String;
  tmpFile: TMemIniFile;

  procedure AddEmuVersion(listFile: String);
  var
    Version, Description: String;
  begin
    if FileExists(FrontendPath+GetMachineTypeGamesFolder+listFile) then
       begin
         tmpFile:= TMemIniFile.Create(FrontendPath+GetMachineTypeGamesFolder+listFile);
         Description:= tmpFile.ReadString('info_file', 'description', '');
         Version:= tmpFile.ReadString('info_file', 'version', '');
         if (Description <> '') and (Version <> '') then
            begin
              if msgString <> '' then
                 msgString:= msgString+#13#10+Description+#13#10+'  -> '+Version
              else
                 msgString:= Description+#13#10+'  -> '+Version;
            end;
         FreeAndNil(tmpFile);
       end;
  end;

begin
  msgString:= '';
  AddEmuVersion(GetSystemFileName(1));
  AddEmuVersion(GetSystemFileName(2));
  AddEmuVersion(GetSystemFileName(3));
  AddEmuVersion(GetSystemFileName(4));
  AddEmuVersion(GetSystemFileName(5));
  AddEmuVersion(GetSystemFileName(6));
  if msgString <> '' then
     GenerateMessage('Games List Versions', 'These are the emulators used to build games lists:'+#13#10+#13#10+msgString, 2);
end;

procedure TFormMain.PopupRefreshAvailableGamesZiNcClick(Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 2);
end;

procedure TFormMain.PopupRefreshAvailableGamesDaphneClick(Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 3);
end;

procedure TFormMain.PopupRefreshAvailableGamesAGEMAMEClick(
  Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 4);
end;

procedure TFormMain.PopupRefreshAvailableGamesPinMAMEClick(
  Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 5);
end;

procedure TFormMain.BcDrawModuleDrawMenuItem(Sender: TObject;
  AMenuItem: TMenuItem; ACanvas: TCanvas; ARect: TRect;
  State: TOwnerDrawState; ABarVisible: Boolean; var DefaultDraw: Boolean);
var
  R: TRect;
  ImageList: TCustomImageList;
  //strShortCut, FullCaption: String;

  procedure DrawCheckedPattern(Inflate: Boolean);
  begin
    if odChecked in State then
    begin
      if Inflate then InflateRect(R, -2, -2);
      ACanvas.Brush.Color:= clBlack;
      ACanvas.FrameRect(R);
      if Inflate then InflateRect(R, 2, 2);
    end;
  end;

begin
  DefaultDraw:= False;
  // menuitem drawing
  if (AMenuItem.Caption = cLineCaption) then
  begin
    // draw line with hints
    // background
    DrawGradient(ACanvas, ARect, 16777215, 15657958, gsHorizontal);

    // align the text and draw it
    R:= ARect;
    R.Left:= R.Right - ACanvas.TextWidth(AMenuItem.Hint) - 15;
    ACanvas.Brush.Style:= bsClear;
    DrawText(ACanvas.Handle,
      PChar(AMenuItem.Hint), Length(AMenuItem.Hint),
      R, 0);

    // draw the line so that it won't draw over text
    R:= ARect;
    Inc(R.Top, (R.Bottom - R.Top) div 2);
    R.Bottom:= R.Top + 1;
    Dec(R.Right, ACanvas.TextWidth(AMenuItem.Hint) + 10 + 10);
    ACanvas.Brush.Color:= clGray; // 16770010;
    ACanvas.FillRect(R);
  end else
  begin
    // use default drawing for mainmenu top items
    if IsInTopMainMenu(AMenuItem) then
    begin
      DefaultDraw:= True;
      Exit;
    end;
    with ACanvas do
    begin
      // draw selected items
      if AMenuItem.Default then
         Font.Style:= Font.Style+[fsBold];
      R:= ARect;
      if odSelected in State then
      begin
        // draw frame and selection gradient
        Brush.Color:= 16435381;
        FrameRect(R);
        InflateRect(R, -2, -2);
        DrawGradient(ACanvas, R, 16772325, 16768205, gsVertical);
        DrawCheckedPattern(False);

        Inc(R.Left, 36);
        Font.Color:= clBlack; // caption color
      end else
      begin
        // draw not selected items
        // draw background gradient
        DrawGradient(ACanvas, ARect, 16777215, 15657958, gsHorizontal);
        DrawCheckedPattern(True);
        // leave space for menuitem image
        Inc(R.Left, 38);
        Font.Color:= clBlack; // caption color
      end;
      if (odDisabled in State) or (odGrayed in State) then
        Font.Color:= clGrayText;

      // draw caption
      InflateRect(R, 0, -(
        (R.Bottom - R.Top - TextHeight(AMenuItem.Caption) - 1)
         div 2));
      Brush.Style:= bsClear;

      //if ShortCutToText(AMenuItem.ShortCut) = '' then
      DrawText(Handle,
        PChar(AMenuItem.Caption), Length(AMenuItem.Caption),
        R, 0);
      //else
      //   begin
      //     strShortCut:= ShortCutToText(AMenuItem.ShortCut);
      //     FullCaption:= AMenuItem.Caption+IntToStr(Length(Char(#9)))+strShortCut;
      //     DrawText(Handle, PChar(FullCaption), Length(FullCaption), R, 0);
      //   end;

      // draw menuitem image
      with AMenuItem do
      begin
        ImageList:= GetImageList;
        if (ImageIndex <> -1) and Assigned(ImageList) then
          ImageList.Draw(ACanvas, ARect.Left + 11,
            ARect.Top + (ARect.Bottom - ARect.Top - ImageList.Height) div 2, ImageIndex);
      end;
    end;
  end;
end;

procedure TFormMain.BcDrawModuleMeasureMenuItem(Sender: TObject;
  AMenuItem: TMenuItem; ACanvas: TCanvas; var Width, Height: Integer;
  ABarVisible: Boolean; var DefaultMeasure: Boolean);
begin
  if not IsInTopMainMenu(AMenuItem) then
  begin
    DefaultMeasure:= False;
    if not (AMenuItem.Caption = cLineCaption) then
    begin
      Height:= 28;
      Width:= Width + 32;
    end;
  end;
end;

procedure TFormMain.MainMenuMeasureMenuItem(Sender: TObject;
  AMenuItem: TMenuItem; ACanvas: TCanvas; var Width, Height: Integer;
  ABarVisible: Boolean; var DefaultMeasure: Boolean);
begin
  if (GetMenuBarMenusIntf(TMenu(Sender)).UseMenuStyle = msWindowsXP) then
     Height:= Height+2;
end;

procedure TFormMain.MenuMAMESelectInputFileClick(Sender: TObject);
var
  Loop: Integer;

  procedure LoadInputFolders(SystemID: Integer);
  var
    MAMEIniFile: THashedStringList;
    TextLine, ExecutableString, IniFile: String;
    Loop2: Integer;
  begin
    ExecutableString:= EmulatorFile[SystemID];
    if (not FileExists(ExecutableString)) or (ExecutableString = '') then
       Exit;

    iniFile:= GetMAMEIniFileName(ExecutableString, SystemID);
    if not FileExists(iniFile) then
       Exit;

    MAMEIniFile:= THashedStringList.Create;
    MAMEIniFile.LoadFromFile(iniFile);
    for Loop2:=0 to MAMEIniFile.Count -1 do
    begin
      TextLine:= MAMEIniFile[Loop2];
      if Copy(TextLine, 1, 16) = 'input_directory ' then
         begin
           InputDir[SystemID]:= ExtractMAMEIniValue(TextLine);
           Break;
         end;
    end;
    FreeAndNil(MAMEIniFile);

     // MAME based only
     if SystemID in [1, 4, 5, 6] then
        begin
          if InputDir[SystemID] = '' then
             InputDir[SystemID]:= ExtractFilePath(ExecutableString)+'inp'
          else
             begin
               if Pos(':', InputDir[SystemID]) = 0 then
                  InputDir[SystemID]:= ExtractFilePath(ExecutableString)+InputDir[SystemID];
             end;
        end;
  end;

begin
  case MenuMAMESelectInputFile.Checked of
    True:
      begin
        try
          for Loop:= 1 to MaxArcadeSystems do
              InputDir[Loop]:= '';
          LoadInputFolders(1); // MAME
          LoadInputFolders(4); // AGEMAME
          LoadInputFolders(5); // PinMAME
          LoadInputFolders(6); // HazeMD
        except
          GenerateMessage('Error', 'Could not define memory variables for input directories.'+#13#10+
                          'Feature not available. Try restarting the frontend.', 2);
          MenuMAMESelectInputFile.Click;
          Exit;
        end;
      end;
    False:
      begin
        for Loop:= 1 to MaxArcadeSystems do
            Finalize(InputDir);
      end;
  end;
end;

function TFormMain.GetInputFileName(Recording: Boolean = False): String;
var
  Loop: Integer;
  List_inp: THashedStringList;
  time_dateResult: String;
begin
  Result:= '';
  if not GetGameData(SelectedNode) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  List_inp:= THashedStringList.Create;
  GetFilesList(InputDir[SystemID_Number], '.inp', GameInfoData.eName+'*.inp', List_inp, False, True, True);
  if List_inp.Count > 0 then
     begin
       if not Assigned(FormLoadInputFile) then
          FormLoadInputFile:= TFormLoadInputFile.Create(nil);
       FormLoadInputFile.InputFilesFolder.Text:= InputDir[SystemID_Number];
       FormLoadInputFile.InputFiles.Items.BeginUpdate;
       for Loop:= 0 to List_inp.Count-1 do
       begin
         with FormLoadInputFile.InputFiles.Items.Add do
         begin
           ImageIndex:= 23;
           Caption:= ExtractFileName(List_inp[Loop]);
           time_dateResult:= '';
           DateTimeToString(time_dateResult, 'mmm/dd/yyyy - hh:nn:ss AM/PM',
                            FileDateToDateTime(FileAge(List_inp[Loop])));
           SubItems.Add(time_dateResult);
           SubItems.Add(List_inp[Loop]);
         end;
       end;
       FormLoadInputFile.InputFiles.Items.EndUpdate;
       if Recording then
          begin
            FormLoadInputFile.Caption:= 'Record an Input File';
            FormLoadInputFile.RecordInputFileName.Visible:= True;
            FormLoadInputFile.ButtonClearRecordInputFilename.Visible:= True;
          end;

       FormLoadInputFile.ShowModal;
       if FormLoadInputFile.MsgResult = mrOk then
          begin
            case Recording of
              False:
                begin
                  if FormLoadInputFile.InputFiles.Selected <> nil then
                     Result:= FormLoadInputFile.InputFiles.Selected.Caption;
                end;
              True:
                begin
                  if (FormLoadInputFile.RecordInputFilename.Text <> '') and
                     (FormLoadInputFile.RecordInputFilename.Text <> '<New Input Filename>') then
                     Result:= FormLoadInputFile.RecordInputFilename.Text
                  else
                     begin
                       if FormLoadInputFile.InputFiles.Selected <> nil then
                          Result:= FormLoadInputFile.InputFiles.Selected.Caption;
                     end;
                end;
            end;
            if Result <> '' then
               begin
                 Result:= LongToShortPath(IncludeTrailingPathDelimiter(FormLoadInputFile.InputFilesFolder.Text)+Result);
                 Result:= ExtractFileName(Result);
               end;
          end;
       FreeAndNil(FormLoadInputFile);
     end
  else
     GenerateMessage('Information', 'No input files were found for "'+
                     mDescription+'"!.', 2);
  FreeAndNil(List_inp);
end;

procedure TFormMain.ButtonViewModeStandardClick(Sender: TObject);
begin
  if GamesTreeView.Tag = 1 then
     begin
       if TMenuItem(Sender).ImageIndex = ButtonViewMode.Tag then
          begin
            PopupMenuViewMode.Items[TMenuItem(Sender).ImageIndex].Checked:= True;
            Exit;
          end
       else
          begin
            ResetMAMu_ImageList;
            ButtonViewMode.Tag:= TMenuItem(Sender).ImageIndex;
            ButtonViewMode.Tag:= TMenuItem(Sender).ImageIndex;
            FocusGamesList;
            SetGameType(SelectedFilterName, True);
          end;
     end;

  if ButtonViewMode.Tag <> TMenuItem(Sender).ImageIndex then
     ButtonViewMode.Tag:= TMenuItem(Sender).ImageIndex;
  PopupMenuViewMode.Items[TMenuItem(Sender).ImageIndex].Checked:= TMenuItem(Sender).Checked;
  SetIcon(IL_ViewMode_Large, IL_ToolBarButtons, ButtonViewMode.Tag, 0);
  if TMenuItem(Sender).ImageIndex = 0 then
     GamesTreeView.TreeOptions.PaintOptions:= GamesTreeView.TreeOptions.PaintOptions - [toShowRoot] // standard
  else
     FormPreferences.TreeViewTreeRoot.OnClick(Self); // grouped modes
end;

procedure TFormMain.PopupShowSreensAllClick(Sender: TObject);
begin
  if TMenuItem(Sender).Tag = ButtonGameFilterNumberScreens.Tag then
     begin
       TMenuItem(Sender).Checked:= True;
       Exit;
     end;
  if TMenuItem(Sender).Checked then
     begin
       ButtonGameFilterNumberScreens.Tag:= TMenuItem(Sender).Tag;
       SetGameType(SelectedFilterName, False);
     end;
end;

function DetectDisplayDevices(StringListHolder: TStringList): Boolean;
var
  lpDisplayDevice: TDisplayDevice;
  dwFlags: DWORD;
  cc: DWORD;
begin
  lpDisplayDevice.cb := sizeof(lpDisplayDevice);
  dwFlags := 0;
  cc:= 0;
  if not Assigned(StringListHolder) then
     StringListHolder:= TStringList.Create;
  while EnumDisplayDevices(nil, cc, lpDisplayDevice , dwFlags) do
  begin
    ShowMessage(lpDisplayDevice.DeviceName+' -> '+lpDisplayDevice.DeviceString);
    Inc(cc);
    StringListHolder.Add(lpDisplayDevice.DeviceName);
    //StringListHolder.Add(lpDisplayDevice.DeviceString); //there is also additional information in lpDisplayDevice

  end;
  Result:= StringListHolder.Count > 0;
end;

function DetectDisplayResolutions(strDeviceName: String; StringListHolder: TStringList): Boolean;
var
    dmTemp: DevMode;
    i: Integer;
begin
  i := 0;
  while EnumDisplaySettings(PAnsiChar(strDeviceName), i, dmTemp) do
  begin
    StringListHolder.Add(IntToStr(dmTemp.dmPelsWidth)+'x'+IntToStr(dmTemp.dmPelsHeight)+'x'+IntToStr(dmTemp.dmBitsPerPel)+'@'+IntToStr(dmTemp.dmDisplayFrequency));
    //read the following properties from the DevMode Structure and do what you need to do
    //    dmBitsPerPel
    //dmPelsWidth
    //dmPelsHeight
    //dmDisplayFlags
    //dmDisplayFrequency
    Inc(i);
  end;
  //rList.SaveToFile('c:\reslist.txt');
  Result:= StringListHolder.Count > 0;
end;

procedure TFormMain.detectvideo1Click(Sender: TObject);
var
  ScreenDevicesList, ResolutionsList: TStringList;
  Loop: ShortInt;
begin
  ScreenDevicesList:= TStringList.Create;
  DetectDisplayDevices(ScreenDevicesList);
  if ScreenDevicesList.Count > 0 then
     begin
       ShowMessage(ScreenDevicesList.Text);
       ResolutionsList:= TStringList.Create;
       for Loop:=0 to ScreenDevicesList.Count-1 do
       begin
         DetectDisplayResolutions(ScreenDevicesList[Loop], ResolutionsList);
         ShowMessage(ResolutionsList.Text);
       end;
     end;
  FreeAndNil(ScreenDevicesList);
  FreeAndNil(ResolutionsList);
end;

procedure TFormMain.PopupIconSizeStandardClick(Sender: TObject);
var
  Node: PVirtualNode;
begin
  if (TMenuItem(Sender).Tag = PopupGameIconSize.Tag) and
     (GamesTreeView.Tag = 1) then
     begin
       if not TMenuItem(Sender).Checked then
          TMenuItem(Sender).Checked:= True;
       Exit;
     end;
  PopupGameIconSize.Tag:= TMenuItem(Sender).Tag;
  case TMenuItem(Sender).Tag of
    0:
      begin
        GamesTreeView.Images:= IL_StandardIconsLarge;
        GamesTreeView.DefaultNodeHeight:= 34;
      end;
    1:
      begin
        GamesTreeView.Images:= IL_StandardIconsStandard;
        GamesTreeView.DefaultNodeHeight:= 26;
      end;
    2:
      begin
        GamesTreeView.Images:= IL_StandardIconsSmall;
        GamesTreeView.DefaultNodeHeight:= 18;
      end;
  end;

  if GamesTreeView.Tag = 1 then
     begin
       ResetMAMu_ImageList;
       if CheckTotal(GamesTreeView) then
          begin
            GamesTreeView.BeginUpdate;
            Node:= GamesTreeView.GetFirst;
            repeat
              GamesTreeView.NodeHeight[Node]:= GamesTreeView.DefaultNodeHeight;
              Node:= GamesTreeView.GetNext(Node);
            until (not Assigned(Node));
            GamesTreeView.EndUpdate;
            if GamesTreeView.SelectedCount > 0 then
               GamesTreeView.ScrollIntoView(SelectedNode, True);
          end;
     end;
end;

procedure TFormMain.MenuStandardStatusBarClick(Sender: TObject);
begin
  MenuStatusBarSize.Tag:= TMenuItem(Sender).Tag;
  StatusBarPanel.AutoSize:= True;
  case MenuStatusBarSize.Tag of
    0:
      begin
        IL_StatusBar.Width:= 32;
        IL_StatusBar.Height:= 32;
      end;
    1:
      begin
        IL_StatusBar.Width:= 24;
        IL_StatusBar.Height:= 24;
      end;
    2:
      begin
        IL_StatusBar.Width:= 16;
        IL_StatusBar.Height:= 16;
      end;
  end;
  if LoadStatusBarIcons then
     UpdateStatusBarGame;
  StatusBarPanel.AutoSize:= False;
  StatusBarPanel.Height:= StatusBarPanel.Height+1;
end;

procedure TFormMain.MenuViewGameDetailsClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if IsSystemEntry(GameInfoData.eDriverName) then
     Exit;
  GetSystemID(GameInfoData.eROMIdentification);
  if not Assigned(FormGameDetails) then
     FormGameDetails:= TFormGameDetails.Create(nil);

  FormGameDetails.GetROMsFiles:= Check_ROMsData_File(SystemID_Number);
  FormGameDetails.ShowModal;
  FreeAndNil(FormGameDetails);
end;

procedure TFormMain.MenuViewFullScreenClick(Sender: TObject);
var
  Loop: ShortInt;
begin
  Separator_FullScreen.Visible:= MenuViewFullScreen.Checked;
  PopupReturnToWindowMode.Visible:= MenuViewFullScreen.Checked;
  PopupExitApplication.Visible:= MenuViewFullScreen.Checked;

  MainMenu.BeginUpdate;
  for Loop:=0 to MainMenu.Items.Count-1 do
      MainMenu.Items[Loop].Visible:= not MenuViewFullScreen.Checked;
  MainMenu.EndUpdate;

  case MenuViewFullScreen.Checked of
    True:
      begin
        if FormMain.WindowState = wsMaximized then
           begin
             MenuViewFullScreen.Tag:= 1;
             FormMain.WindowState:= wsNormal;
           end;
        FormMainWidth:= FormMain.Width;
        FormMainHeight:= FormMain.Height;
        FormMainTop:= FormMain.Top;
        FormMainLeft:= FormMain.Left;
        if ToolBarPanel.Tag = 1 then
           ToolbarPanel.Visible:= False;
        if StatusBarPanel.Tag = 1 then
           StatusBarPanel.Visible:= False;

        SetWindowLong(FormMain.Handle, GWL_STYLE, GetWindowLong(FormMain.Handle, GWL_STYLE) and not WS_CAPTION);
        SetWindowPos(FormMain.Handle, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
                     GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW or SWP_NOACTIVATE);
        SetForegroundWindow(FormMain.Handle);
        SetActiveWindow(Application.Handle);
      end;
    False:
      begin
        SetWindowLong(FormMain.Handle, GWL_STYLE, GetWindowLong(FormMain.Handle, GWL_STYLE) or WS_CAPTION);
        SetWindowPos(FormMain.Handle, HWND_TOP, 0, 0, GetSystemMetrics(SM_CXSCREEN),
                     GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW or SWP_NOACTIVATE);
        SetForegroundWindow(FormMain.Handle);
        SetActiveWindow(Application.Handle);
        LockWindowUpdate(FormMain.Handle);
        FormMain.WindowState:= wsNormal;

        // Make the form normal
        MoveWindow(FormMain.Handle, FormMainLeft, FormMainTop, FormMainWidth, FormMainHeight, True);
        LockWindowUpdate(0);

        if ToolBarPanel.Tag = 1 then
           ToolbarPanel.Visible:= True;
        if StatusBarPanel.Tag = 1 then
           StatusBarPanel.Visible:= True;
        if MenuViewFullScreen.Tag = 1 then
           FormMain.WindowState:= wsMaximized;
      end;
  end;
  FormMain.Refresh;
  Application.ProcessMessages;
  FocusGamesList;
end;

procedure TFormMain.PopupReturnToWindowModeClick(Sender: TObject);
begin
  MenuViewFullScreen.Click;
end;

procedure TFormMain.PopupImageInfoClick(Sender: TObject);
var
  StringLine: String;
begin
  StringLine:= 'File: '+ ImageDetails[1].FileName;
  if ImageDetails[1].ZipFileName <> '' then
     StringLine:= StringLine+#13#10+Format('Zip: %s', [ImageDetails[1].ZipFileName]);
  StringLine:= StringLine+#13#10+'Resolution: '+IntToStr(ImageDetails[1].ResolutionX)+'x'+
               IntToStr(ImageDetails[1].ResolutionY);
  if (ImageDetails[1].AspectRatioResolutionX <> -1) and (ImageDetails[1].AspectRatioResolutionY <> -1) then
     StringLine:= StringLine+#13#10+'Screen Resolution: '+IntToStr(ImageDetails[1].AspectRatioResolutionX)+'x'+
               IntToStr(ImageDetails[1].AspectRatioResolutionY);
  GenerateMessage('Image Details', StringLine, 2);
end;

procedure TFormMain.PopupSetGameCustomCommandLineClick(Sender: TObject);
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  if GameInfoData.eName <> '' then
     begin
       if not Assigned(FormCustomCommandLine) then
          FormCustomCommandLine:= TFormCustomCommandLine.Create(nil);
       FormCustomCommandLine.ImageGameIcon.Tag:= TMenuItem(Sender).Tag; // 0=game; 1=driver; 2=system
       FormCustomCommandLine.ShowModal;
       FreeAndNil(FormCustomCommandLine);
       SetCurrentDir(FrontendPath);
     end;
end;

procedure TFormMain.PopupDeleteGameCustomCommandLineClick(Sender: TObject);
var
  System, sFileName: String;
begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;
  System:= GetSystemFolderName(GameInfoData.eROMIdentification)+'\';
  case TMenuItem(Sender).Tag of
    0: sFileName:= GameInfoData.eName;
    1: sFileName:= ChangeFileExt(GameInfoData.eDriverName, '');
    2: sFileName:= System;
  end;
  DeleteCustomCommandLine(sFileName, GameInfoData.eROMIdentification);
end;

procedure TFormMain.PopupCustomSettingsClick(Sender: TObject);
var
  CurrentDriver, CurrentSystem: String;

  procedure ToggleOptions(Filename: String; PopupSetName, PopupDeleteName: TMenuItem);
  begin
    PopupSetName.Enabled:= True;
    if SystemID_Number <> 2 then
       PopupDeleteName.Enabled:= FileExists(IncludeTrailingPathDelimiter(FullEmuFolderFix(IniFilesDir[SystemID_Number], SystemID_Number))+Filename)
    else
       PopupDeleteName.Enabled:= FileExists(GetFolderZiNc_cfg+FileName);
  end;

begin
  if not CheckSelected(GamesTreeView) then
     Exit;
  if not GetGameData(SelectedNode) then
     Exit;

  // set captions
  PopupSetCustomOptions.Caption:= Format(PopupSetCustomOptions.Hint, [GameInfoData.eName]);
  PopupDeleteCustomOptions.Caption:= Format(PopupDeleteCustomOptions.Hint, [GameInfoData.eName]);

  PopupSetGameDriverCustomOptions.Caption:= Format(PopupSetCustomOptions.Hint, [GameInfoData.eDriverName]);
  PopupDeleteGameDriverCustomOptions.Caption:= Format(PopupDeleteCustomOptions.Hint, [GameInfoData.eDriverName]);

  PopupSetGameCustomCommandLine.Caption:= Format(PopupSetGameCustomCommandLine.Hint, [GameInfoData.eName]);
  PopupDeleteGameCustomCommandLine.Caption:= Format(PopupDeleteGameCustomCommandLine.Hint, [GameInfoData.eName]);
  PopupSetDriverCustomCommandLine.Caption:= Format(PopupSetGameCustomCommandLine.Hint, [GameInfoData.eDriverName]);
  PopupDeleteDriverCustomCommandLine.Caption:= Format(PopupDeleteGameCustomCommandLine.Hint, [GameInfoData.eDriverName]);
  PopupSetSystemCustomCommandLine.Caption:= Format(PopupSetGameCustomCommandLine.Hint, [GetSystemFolderName(GameInfoData.eROMIdentification)]);
  PopupDeleteSystemCustomCommandLine.Caption:= Format(PopupDeleteGameCustomCommandLine.Hint, [GetSystemFolderName(GameInfoData.eROMIdentification)]);
  // end of set captions
  
  GetSystemID(GameInfoData.eROMIdentification);
  CurrentDriver:= ChangeFileExt(GameInfoData.eDriverName, '');
  CurrentSystem:= GetSystemFolderName(GameInfoData.eROMIdentification)+'\';

  PopupDeleteCustomOptions.Enabled:= False;
  PopupDeleteGameDriverCustomOptions.Enabled:= False;
  PopupDeleteGameCustomCommandLine.Enabled:= False;
  PopupDeleteDriverCustomCommandLine.Enabled:= False;

  if GameInfoData.eDescription <> '' then
     begin
       if PopupCustomGameOptions.Enabled then
          begin
            if GameInfoData.eName <> '' then
               begin
                 case SystemID_Number of
                   1, 4, 5, 6:
                     begin
                       ToggleOptions(GameInfoData.eName+'.ini',
                                     PopupSetCustomOptions, PopupDeleteCustomOptions);
                     end;
                   2:
                     ToggleOptions(GameInfoData.eName+'.cfg',
                                   PopupSetCustomOptions, PopupDeleteCustomOptions);
                 end;
               end;
          end;

          if CurrentDriver <> '' then
             begin
               case SystemID_Number of
                 1, 4, 5, 6:
                   begin
                     ToggleOptions(CurrentDriver+'.ini',
                                   PopupSetGameDriverCustomOptions, PopupDeleteGameDriverCustomOptions);
                   end;
                 2:
                   ToggleOptions(CurrentDriver+'.cfg',
                                 PopupSetGameDriverCustomOptions, PopupDeleteGameDriverCustomOptions);
               end;

               PopupDeleteGameCustomCommandLine.Enabled:= FileExists(FrontendPath+'ini_files\cmdline\'+CurrentSystem+GameInfoData.eName+'.ini');
               PopupDeleteDriverCustomCommandLine.Enabled:= FileExists(FrontendPath+'ini_files\cmdline\'+CurrentSystem+CurrentDriver+'.ini');
               PopupDeleteSystemCustomCommandLine.Enabled:= FileExists(FrontendPath+'ini_files\cmdline\'+CurrentSystem+CurrentSystem+'.ini');
             end;

          if SystemID_Number in [1, 4, 5, 6] then
             ToggleOptions('debug.ini',
                           PopupSetDebugCustomOptions, PopupDeleteDebugCustomOptions);
     end;
end;

procedure TFormMain.CustomGamesEditor1Click(Sender: TObject);
begin
  GenerateMessage('Warning', 'This feature is not working yet. Nothing is saved, '+
                  'no matter what changes you have made. It is loading the MAME games list, '+
                  'but this is just for testing and debugging.'+#13#10+'Select a '+
                  'game and then you can edit it.', 2);
  if not Assigned(FormCustomGamesEditor) then
     FormCustomGamesEditor:= TFormCustomGamesEditor.Create(nil);
  FormCustomGamesEditor.ShowModal;
  FreeAndNil(FormCustomGamesEditor);
end;

procedure TFormMain.MenuViewForceQuotesCommandLineClick(Sender: TObject);
begin
  if Win32Platform <> 2 then
     Exit;
  case MenuViewForceQuotesCommandLine.Checked of
    True : WinQuotesStr:= '"';
    False: WinQuotesStr:= '';
  end;
end;

procedure TFormMain.MenuViewCPUFilterBoxClick(Sender: TObject);
begin
  ToolBarCPUFilter.Visible:= MenuViewCPUFilterBox.Checked;
end;

procedure TFormMain.ButtonFilterCPUApplyClick(Sender: TObject);
var
  Node: PVirtualNode;
  Data: pGameInfo;
  KeepGame: Boolean;
begin
  if CheckTotal(GamesTreeView) then
     begin
       if (FilterCPU.Text = '') and
          (FilterCPUList.ItemIndex = 0) then
          begin
            SetGameType(SelectedFilterName, False);
            Exit;
          end
       else
          begin
            // MAME based systems only
            Node:= GamesTreeView.GetFirst;
            KeepGame:= True;
            GamesTreeView.BeginUpdate;
            repeat
              if GamesTreeView.IsVisible[Node] then
                 begin
                    Data:= GamesTreeView.GetNodeData(Node);
                    if Data.eROMIdentification in [00..05, 14..29] then
                       begin
                         if FilterCPU.Text <> '' then
                            KeepGame:= CompareText(Data.eChipCPU, FilterCPU.Text) = 0
                         else
                            begin
                              if FilterCPUList.ItemIndex > 0 then
                                 KeepGame:= CompareText(Data.eChipCPU, FilterCPUList.Text) = 0
                            end;
                       end;
                    GamesTreeView.IsVisible[Node]:= KeepGame;
                 end;
              Node:= GamesTreeView.GetNext(Node);
            until Node = nil;
            GamesTreeView.EndUpdate;
            UpdateTotalEntriesLabel;
          end;
     end;
  FocusGamesList;
end;

procedure TFormMain.FilterCPUKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_RETURN then
    ButtonFilterCPUApply.Click;
end;

procedure TFormMain.PopupScanAvailableGamesHazeMDClick(Sender: TObject);
begin
  CallRefreshGames(TMenuItem(Sender).Tag, False, 6);
end;

procedure TFormMain.PopupAuditAllGamesHazeMDClick(Sender: TObject);
begin
  SetAudit(6, TMenuItem(Sender).Tag);
end;

procedure TFormMain.ButtonRandomGameClick(Sender: TObject);
var
  RandomValue: Integer;
  Continue: Boolean;
  NodeIndex: PVirtualNode;
begin
  if not CheckTotalVisible(GamesTreeView) then
     begin
       if MenuRandomGamePreview.Checked then
          MenuRandomGamePreview.Click;
       Exit;
     end;
  Continue:= False;
  repeat
    Randomize;
    RandomValue:= Random(GamesTreeView.TotalCount-1);
    if RandomValue <> SelectedNode.Index then
       begin
         NodeIndex:= GamesTreeView.GetFirstVisible;
         repeat
           if NodeIndex.Index <> RandomValue then
              NodeIndex:= GamesTreeView.GetNextVisible(NodeIndex)
           else
              Continue:= True;
         until (not Assigned(NodeIndex)) or Continue;
       end;
  until (Continue);
  SelectNode(RandomValue);
end;

procedure TFormMain.StatusBar_GameSizeClick(Sender: TObject);
begin
  if MenuGameSizeFormat.Tag = 2 then
     MenuGameSizeFormat.Items[0].Click
  else
     MenuGameSizeFormat.Items[MenuGameSizeFormat.Tag+1].Click;
end;

procedure TFormMain.StatusBar_FavoritesProfileClick(Sender: TObject);
begin
  if MenuFavoriteProfileEditor.Visible then
     MenuFavoriteProfileEditor.Click;
end;

procedure TFormMain.MenuGameSizeBitsClick(Sender: TObject);
begin
  MenuGameSizeFormat.Tag:= TMenuItem(Sender).Tag;
  if StatusBar_GameSize.Visible and FormMain.Visible then
     StatusBar_GameSize.Caption:= UpdateGameSize;
  case MenuGameSizeFormat.Tag of
    0:
      begin
        StatusBar_GameSize.Hint:= 'Game size [emulator], in bits';
        StatusBar_GameSize.ImageIndex:= 1;
      end;
    1:
      begin
        StatusBar_GameSize.Hint:= 'Game size [emulator], in bytes';
        StatusBar_GameSize.ImageIndex:= 1;
      end;
    2:
      begin
        StatusBar_GameSize.Hint:= 'Game size [zip file], in bytes';
        StatusBar_GameSize.ImageIndex:= 2;
      end;
  end;

end;

procedure TFormMain.MenuStatusBarSettingsClick(Sender: TObject);
begin
  if not Assigned(FormStatusBarEditor) then
     FormStatusBarEditor:= TFormStatusBarEditor.Create(nil);
  FormStatusBarEditor.ShowModal;
  FreeAndNil(FormStatusBarEditor);
end;

procedure TFormMain.ToolBarStatusBarMouseDown(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbRight then
     MenuStatusBarSettings.Click;
end;

procedure TFormMain.MenuImagesConverttoOldFormatClick(Sender: TObject);
begin
  GenerateMessage('Warning', 'Feature not fully implemented yet. '+
                  'You cannot convert filenames, but you can use the scan feature.', 2);
  if not Assigned(FormConvertImages) then
     FormConvertImages:= TFormConvertImages.Create(nil);
  //FormNotUsed.LabelFeatureDescription.Caption:= 'Select a system, then select '+
  //        'an image type. Click on button "Scan". Check all items you want to delete, if files '+
  //        'were found, and click on button "Delete". The files listed do not belong to any game in '+
  //        'your games list. They can all be excluded.';
  FormConvertImages.ShowModal;
  FreeAndNil(FormConvertImages);
end;

procedure TFormMain.PopupGameDocsFeatureNotAvailableClick(Sender: TObject);
begin
  GenerateMessage('Information', 'If you are reading this, it means that you need '+
                  'to place the following files into the root folder of MAME or the '+
                  '"\ini_files\" sub-folder of Emu Loader: '+
                  '"mameinfo.dat" / "history.dat" / "story.dat".'+#13#10+'Game FAQs files location must '+
                  'be defined at preferences screen, "Folders / Files" tab.', 2);  
end;

procedure TFormMain.PopupDeleteMultipleZipFileNamesClick(Sender: TObject);
begin
  if not Assigned(FormDeleteMultipleGamesFiles) then
     FormDeleteMultipleGamesFiles:= TFormDeleteMultipleGamesFiles.Create(nil);
  FormDeleteMultipleGamesFiles.ShowModal;
  FreeAndNil(FormDeleteMultipleGamesFiles);
end;

procedure TFormMain.MenuGamesEnableMultipleSelectionClick(Sender: TObject);
begin
  GamesTreeView.BeginUpdate;
  case MenuGamesEnableMultipleSelection.Checked of
    True : GamesTreeView.TreeOptions.SelectionOptions:= GamesTreeView.TreeOptions.SelectionOptions+[toMultiSelect];
    False: GamesTreeView.TreeOptions.SelectionOptions:= GamesTreeView.TreeOptions.SelectionOptions-[toMultiSelect];
  end;
  GamesTreeView.EndUpdate;
  if CheckTotalVisible(GamesTreeView) then
     SelectNode(SelectedNode.Index);
end;

procedure TFormMain.MenuIncrementalSearchDescriptionClick(Sender: TObject);
begin
  MenuIncrementalSearch.Tag:= TMenuItem(Sender).Tag;
end;

procedure TFormMain.PopupIconsClick(Sender: TObject);
begin
  if not PopupGamesUseMAMu_Icons.Checked then
     PopupGamesUseMAMu_Icons.Enabled:= FormPreferences.MAMu_Icons.Text <> '';
end;

procedure TFormMain.PopupRefreshGamesClick(Sender: TObject);
begin
  PopupRefreshSelectedGame.Enabled:= GamesTreeView.SelectedCount = 1;
end;

procedure TFormMain.PopupAuditGamesClick(Sender: TObject);
begin
  PopupAuditSelectedGame.Enabled:= GamesTreeView.SelectedCount = 1;
end;

procedure TFormMain.PopupFavoriteGamesClick(Sender: TObject);
begin
  if PopupAddToFavorites.Visible then
     PopupAddToFavorites.Enabled:= CheckSelected(GamesTreeView);
  if PopupDeleteFromFavorites.Visible then
     PopupDeleteFromFavorites.Enabled:= CheckSelected(GamesTreeView);
end;

procedure TFormMain.PopupGameStoryClick(Sender: TObject);
begin
  if (not CheckSelected(GamesTreeView)) or PopupAutomaticGameInformation.Checked then
     Exit;
  ShowGameInfoAll(5);
end;

procedure TFormMain.MenuReloadFrontendIconsClick(Sender: TObject);
begin
  LoadFrontendIcons;
end;

procedure TFormMain.ReloadGamesListIcons1Click(Sender: TObject);
begin
  if CheckDefaultIconsFile and CheckTotal(GamesTreeView) then
     begin
       if not PopupGamesUseMAMu_Icons.Checked then
          GamesTreeView.BeginUpdate;
       IL_StandardIconsLarge.Clear;
       IL_StandardIconsStandard.Clear;
       IL_StandardIconsSmall.Clear;
       ReadDefaultIconsFile;
       if not PopupGamesUseMAMu_Icons.Checked then
          begin
            GamesTreeView.Refresh;
            GamesTreeView.EndUpdate;
          end;
     end;
end;

procedure TFormMain.PopupGameDocsEnableToolBarClick(Sender: TObject);
begin
  GameDocumentsToolBarPanel.Visible:= PopupGameDocsEnableToolBar.Checked;
end;

procedure TFormMain.SetLayoutGameDocuments;

  procedure SetAllNone;
  begin
    SplitterMAMEInfo.Align:= alNone;
    PanelImage.Align:= alNone;
    PanelGameDocuments.Align:= alNone;
  end;

begin
  if (PanelGameDocuments.Align = alClient) and (not MenuShowImages.Checked) then
     Exit;
  SetAllNone;

  case PanelGameDocuments.Tag of
    0: // info top, images bottom
      begin
        PanelGameDocuments.Align:= alTop;
        PanelGameDocuments.Height:=  GameDocumentsLayout1_Top.Tag;
        SplitterMAMEInfo.Height:= 2;
        SplitterMAMEInfo.Top:= PanelGameDocuments.Height+2;
        SplitterMAMEInfo.Align:= alTop;
      end;
    1: // info bottom, images top
      begin
        PanelGameDocuments.Align:= alBottom;
        PanelGameDocuments.Height:= GameDocumentsLayout2_Bottom.Tag;
        SplitterMAMEInfo.Height:= 2;
        SplitterMAMEInfo.Top:= PanelGameDocuments.Top-2;
        SplitterMAMEInfo.Align:= alBottom;
      end;
    2: // info left, images right
      begin
        // info.align:= alLeft;
        // splitter.align:= alLeft;
        // panelimages.align:= alClient;
        PanelGameDocuments.Align:= alLeft;
        PanelGameDocuments.Width:= GameDocumentsLayout3_Left.Tag;
        SplitterMAMEInfo.Width:= 2;
        SplitterMAMEInfo.Left:= PanelGameDocuments.Width+2;
        SplitterMAMEInfo.Align:= alLeft;
      end;
    3: // info right, images left
      begin
        // info.align:= alRight;
        // splitter.align:= alRight;
        // panelimages.align:= alClient;
        PanelGameDocuments.Align:= alRight;
        PanelGameDocuments.Width:= GameDocumentsLayout4_Right.Tag;
        SplitterMAMEInfo.Width:= 2;
        SplitterMAMEInfo.Left:= PanelGameDocuments.Left-2;
        SplitterMAMEInfo.Align:= alRight;
      end;
  end;
  PanelImage.Align:= alClient;
end;

procedure TFormMain.SplitterMAMEInfoCanResize(Sender: TObject;
  var NewSize: Integer; var Accept: Boolean);
begin
  if (PanelGameDocuments.Align = alClient) or
     (not PanelGameDocuments.Visible) or
     (not SplitterMAMEInfo.Visible) then
     Exit;
  case PanelGameDocuments.Tag of
    0:
      begin
        if GameDocumentsLayout1_Top.Tag <> NewSize then
           GameDocumentsLayout1_Top.Tag:= NewSize;
      end;
    1:
      begin
        if GameDocumentsLayout2_Bottom.Tag <> NewSize then
           GameDocumentsLayout2_Bottom.Tag:= NewSize;
      end;
    2:
      begin
        if GameDocumentsLayout3_Left.Tag <> NewSize then
           GameDocumentsLayout3_Left.Tag:= NewSize;
      end;
    3:
      begin
        if GameDocumentsLayout4_Right.Tag <> NewSize then
           GameDocumentsLayout4_Right.Tag:= NewSize;
      end;
  end;
  // need to code "ReadIni" / "UpdateIni" for these settings
end;

procedure TFormMain.GameDocumentsLayout1_TopClick(Sender: TObject);
begin
  PanelGameDocuments.Tag:= 0;
  SetLayoutGameDocuments;
end;

procedure TFormMain.GameDocumentsLayout2_BottomClick(Sender: TObject);
begin
  PanelGameDocuments.Tag:= 1;
  SetLayoutGameDocuments;
end;

procedure TFormMain.GameDocumentsLayout3_LeftClick(Sender: TObject);
begin
  PanelGameDocuments.Tag:= 2;
  SetLayoutGameDocuments;
end;

procedure TFormMain.GameDocumentsLayout4_RightClick(Sender: TObject);
begin
  PanelGameDocuments.Tag:= 3;
  SetLayoutGameDocuments;
end;

procedure TFormMain.GameDocumentsFontClick(Sender: TObject);
begin
  FontDialog.Font:= MAMEInfoTextHolder.Font;
  if FontDialog.Execute then
     MAMEInfoTextHolder.Font:= FontDialog.Font;
end;

end.

