unit ClientDefs;

interface

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

type
  EClientException = class(Exception);

  TCustomFormCr = class(Forms.TCustomForm);

function GetParentFormSafe(AControl: TControl): TCustomForm;
procedure AssertMainThread;
procedure RestartTimer(ATimer: TTimer);
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;
function DateTimeToStdStr(const T: TDateTime): string;

type
  TTaskDialogHelper = class helper for TTaskDialog
    function ExecuteModally: Boolean; overload;
    function ExecuteModally(ParentWnd: HWND): Boolean; overload;
  end;

const
  ClientFPUCW = Word($133F);

implementation

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

var
  GInvFS: TFormatSettings;

function GetParentFormSafe(AControl: TControl): TCustomForm;
begin
  if Assigned(AControl) then
    Result := GetParentForm(AControl)
  else
    Result := nil;
end;

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;

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;

function DateTimeToStdStr(const T: TDateTime): string;
begin
  if T = 0.0 then
    Result := ''
  else
    Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', T, GInvFS);
end;

{ TTaskDialogHelper }

function TTaskDialogHelper.ExecuteModally: Boolean;
begin
  Application.ModalStarted;
  try
    Result := Execute;
  finally
    Application.ModalFinished;
  end;
end;

function TTaskDialogHelper.ExecuteModally(ParentWnd: HWND): Boolean;
begin
  Application.ModalStarted;
  try
    Result := Execute(ParentWnd);
  finally
    Application.ModalFinished;
  end;
end;

initialization
  GInvFS := TFormatSettings.Invariant;

end.
