{

   Timed dialogs for Free Vision

   Copyright (c) 2004 by Free Pascal core team

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

 ****************************************************************************}
UNIT timeddlg;

{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}
                                  INTERFACE
{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}

{====Include file to sort compiler platform out =====================}
{$I platform.inc}
{====================================================================}

{==== Compiler directives ===========================================}

{$IFNDEF PPC_FPC}{ FPC doesn't support these switches }
  {$F-} { Near calls are okay }
  {$A+} { Word Align Data }
  {$B-} { Allow short circuit boolean evaluations }
  {$O+} { This unit may be overlaid }
  {$G+} { 286 Code optimization - if you're on an 8088 get a real computer }
  {$P-} { Normal string variables }
  {$N-} { No 80x87 code generation }
  {$E+} { Emulation is on }
{$ENDIF}

{$X+} { Extended syntax is ok }
{$R-} { Disable range checking }
{$S-} { Disable Stack Checking }
{$I-} { Disable IO Checking }
{$Q-} { Disable Overflow Checking }
{$V-} { Turn off strict VAR strings }
{====================================================================}

USES objects, dialogs, fvconsts, drivers, views; { Standard GFV unit }

type
  TTimedDialog = object (TDialog)
    Secs: longint;
    constructor Init (var Bounds: TRect; ATitle: TTitleStr; ASecs: word);
    constructor Load (var S: TStream);
    procedure   GetEvent (var Event: TEvent); virtual;
    procedure   Store (var S: TStream); virtual;
  private
    Secs0: longint;
    Secs2: longint;
    DayWrap: boolean;
  end;
  PTimedDialog = ^TTimedDialog;

(* Must be always included in TTimeDialog! *)
  TTimedDialogText = object (TStaticText)
    constructor Init (var Bounds: TRect);
    procedure   GetText (var S: string); virtual;
  end;
  PTimedDialogText = ^TTimedDialogText;

const
  RTimedDialog: TStreamRec = (
    ObjType: idTimedDialog;
{$IFDEF BP_VMTLink}                              { BP style VMT link }
    VmtLink: Ofs (TypeOf (TTimedDialog)^);
{$ELSE}                                          { Alt style VMT link }
    VmtLink: TypeOf (TTimedDialog);
{$ENDIF BP_VMTLink}
    Load:    @TTimedDialog.Load;
    Store:   @TTimedDialog.Store
  );

  RTimedDialogText: TStreamRec = (
    ObjType: idTimedDialogText;
{$IFDEF BP_VMTLink}                              { BP style VMT link }
    VmtLink: Ofs (TypeOf (TTimedDialogText)^);
{$ELSE}                                          { Alt style VMT link }
    VmtLink: TypeOf (TTimedDialogText);
{$ENDIF BP_VMTLink}
    Load:    @TTimedDialogText.Load;
    Store:   @TTimedDialogText.Store
  );

procedure RegisterTimedDialog;

FUNCTION TimedMessageBox (Const Msg: String; Params: Pointer;
  AOptions: Word; ASecs: Word): Word;

{-TimedMessageBoxRect------------------------------------------------
TimedMessageBoxRect allows the specification of a TRect for the message box
to occupy.
---------------------------------------------------------------------}
FUNCTION TimedMessageBoxRect (Var R: TRect; Const Msg: String; Params: Pointer;
  AOptions: Word; ASecs: Word): Word;


{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}
                                IMPLEMENTATION
{<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>}

USES
  dos,
  app, {resource,} msgbox;   { Standard GFV units }


{***************************************************************************}
{                            INTERFACE ROUTINES                             }
{***************************************************************************}

constructor TTimedDialogText.Init (var Bounds: TRect);
begin
  inherited Init (Bounds, '');
end;


procedure TTimedDialogText.GetText (var S: string);
begin
  if Owner <> nil
(* and (TypeOf (Owner^) = TypeOf (TTimedDialog)) *)
                  then
   begin
    Str (PTimedDialog (Owner)^.Secs, S);
    S := #3 + S;
   end
  else
   S := '';
end;



constructor TTimedDialog.Init (var Bounds: TRect; ATitle: TTitleStr;
  ASecs: word);
var
  H, M, S, S100: word;
begin
  inherited Init (Bounds, ATitle);
  GetTime (H, M, S, S100);
  Secs0 := H * 3600 + M * 60 + S;
  Secs2 := Secs0 + ASecs;
  Secs := ASecs;
  DayWrap := Secs2 > 24 * 3600;
end;


procedure TTimedDialog.GetEvent (var Event: TEvent);
var
  H, M, S, S100: word;
  Secs1: longint;
begin
  inherited GetEvent (Event);
  GetTime (H, M, S, S100);
  Secs1 := H * 3600 + M * 60 + S;
  if DayWrap then Inc (Secs1, 24 * 3600);
  if Secs2 - Secs1 <> Secs then
   begin
    Secs := Secs2 - Secs1;
    if Secs < 0 then
     Secs := 0;
(* If remaining seconds are displayed in one of included views, update them. *)
    Redraw;
   end;
  with Event do
   if (Secs = 0) and (What = evNothing) then
    begin
     What := evCommand;
     Command := cmCancel;
    end;
end;


constructor TTimedDialog.Load (var S: TStream);
begin
  inherited Load (S);
  S.Read (Secs, SizeOf (Secs));
  S.Read (Secs0, SizeOf (Secs0));
  S.Read (Secs2, SizeOf (Secs2));
  S.Read (DayWrap, SizeOf (DayWrap));
end;


procedure TTimedDialog.Store (var S: TStream);
begin
  inherited Store (S);
  S.Write (Secs, SizeOf (Secs));
  S.Write (Secs0, SizeOf (Secs0));
  S.Write (Secs2, SizeOf (Secs2));
  S.Write (DayWrap, SizeOf (DayWrap));
end;



function TimedMessageBox (const Msg: string; Params: pointer;
  AOptions: word; ASecs: word): word;
var
  R: TRect;
begin
  R.Assign(0, 0, 40, 10);                            { Assign area }
  if (AOptions AND mfInsertInApp = 0) then           { Non app insert }
   R.Move((Desktop^.Size.X - R.B.X) div 2,
      (Desktop^.Size.Y - R.B.Y) div 2)               { Calculate position }
  else
   R.Move((Application^.Size.X - R.B.X) div 2,
      (Application^.Size.Y - R.B.Y) div 2);          { Calculate position }
  TimedMessageBox := TimedMessageBoxRect (R, Msg, Params,
    AOptions, ASecs);                                { Create message box }
end;


function TimedMessageBoxRect (var R: TRect; const Msg: string; Params: pointer;
  AOptions: word; ASecs: word): word;
var
  Dlg: PTimedDialog;
  TimedText: PTimedDialogText;
begin
  Dlg := New (PTimedDialog, Init (R, MsgBoxTitles [AOptions
    and $3], ASecs));                                { Create dialog }
  with Dlg^ do
   begin
    R.Assign (3, Size.Y - 5, Size.X - 2, Size.Y - 4);
    New (TimedText, Init (R));
    Insert (TimedText);
    R.Assign (3, 2, Size.X - 2, Size.Y - 5);         { Assign area for text }
   end;
  TimedMessageBoxRect := MessageBoxRectDlg (Dlg, R, Msg, Params, AOptions);
  Dispose (Dlg, Done);                               { Dispose of dialog }
end;



procedure RegisterTimedDialog;
begin
  RegisterType (RTimedDialog);
  RegisterType (RTimedDialogText);
end;


begin
  RegisterTimedDialog;
end.
