unit ClientDefs;

interface

uses
  Windows, SysUtils, Types, Classes, UITypes, Controls, Forms, StdCtrls, ExtCtrls;

type
  EClientException = class(Exception);

  TCustomFormCr = class(Forms.TCustomForm);

procedure AssertMainThread;
procedure RestartTimer(ATimer: TTimer);
function _scale(X: Integer): Integer;
procedure ShowText(const S, Title: string);
procedure GUINav(AForm: TCustomFormCr; const AParts: array of TWinControl);
function SanitizeFileName(const AFileName: string): string;
function IntToPrettyStr(AValue: Integer): string;
function IsKeyDown(const VK: Integer): Boolean; inline;

implementation

uses
  Math, StrUtils, DateUtils, IOUtils, ASObjects, Gallery, UxPanel;

procedure AssertMainThread;
begin
  if TThread.Current.ThreadID <> MainThreadID then
    raise Exception.Create('This facility can only be used from the main thread.');
end;

procedure RestartTimer(ATimer: TTimer);
begin
  if ATimer = nil then
    Exit;
  ATimer.Enabled := False;
  ATimer.Enabled := True;
end;

function _scale(X: Integer): Integer;
begin
  Result := MulDiv(X, Screen.PixelsPerInch, 96);
end;

procedure ShowText(const S, Title: string);
var
  Obj: TAlgosimString;
begin
  Obj := ASO(S);
  try
    TGallery.CreateFrame(Obj, Title, True);
  finally
    Obj.Free;
  end;
end;

procedure GUINav(AForm: TCustomFormCr; const AParts: array of TWinControl);
var
  i: Integer;
  j: Integer;
  Part: TWinControl;
  Ctl, Child: TWinControl;
begin

  if Length(AParts) = 0 then
    Exit;

  if AForm = nil then
    Exit;

  if not AForm.Visible then
    Exit;

  Ctl := AForm.ActiveControl;
  if Assigned(Ctl) then
    for i := Low(AParts) to High(AParts) do
      if AParts[i].ContainsControl(Ctl) then
        for j := Succ(i) to i + Length(AParts) - 1 do
        begin
          Part := AParts[j mod Length(AParts)];
          if Part.CanFocus then
          begin
            if Part is TUxPanel then
            begin
              Child := AForm.FindNextControl(Part, True, True, False);
              if Assigned(Child) and Child.CanFocus then
                Child.SetFocus;
              Exit;
            end;
            Part.SetFocus;
            Exit;
          end;
        end;

  if AParts[0].CanFocus then
    AParts[0].SetFocus;

end;

function SanitizeFileName(const AFileName: string): string;
var
  i, c: Integer;
begin
  SetLength(Result, AFileName.Length);
  c := 0;
  for i := 1 to AFileName.Length do
    if TPath.IsValidFileNameChar(AFileName[i]) then
    begin
      Inc(c);
      Result[c] := AFileName[i];
    end;
  SetLength(Result, c);
end;

function IntToPrettyStr(AValue: Integer): string;
begin
  var PrettyIntFS := TFormatSettings.Invariant;
  PrettyIntFS.ThousandSeparator := #32;
  Result := Format('%.0n', [Double(AValue)], PrettyIntFS);
end;

function IsKeyDown(const VK: Integer): Boolean; inline;
begin
  IsKeyDown := GetKeyState(VK) < 0;
end;

end.
