Daniel
2012-01-08 12:05:54
Hello all! :)
I present to you my Progress Report include! Taken from the source header:
Basically it allows a periodic progress report displayed in a separate form, running alongside your script, in the same script! This eliminates the need to paint on the SMART canvas once and for all and the slow/lagginess that induces! This uses form execution methods that haven't been done (from what I can tell) before in Simba or SCAR. Simply put, it;s somewhat multi-threaded :) (well, event-driven really if you want to get technical :p)
I got the idea from somebody around here that said it was "impossible" and "very hard to do" whilst reading a couple of hours ago. :)
It's pretty easy to use! Even look at the following script!
Pretty easy, eh? Everything to do with this (except one, the OnProgressUpdate) has a prefix of Progress_, and the names are pretty easy too! So you can't get confused by it :)
Also, here's the actual include (place it in /SRL/SRL/Misc/Progress.simba):
And damn you Kyle Undefined! This made me stay awake until 4am (couple of hours after you told me what you did to help you "sleep")! :p
I present to you my Progress Report include! Taken from the source header:
The Progress Report Form include allows the execution of periodic script reports specified by the user/scripter in a separate window. This include allows the runtime of a periodic updating form as-well as script execution simultaneously.
Basically it allows a periodic progress report displayed in a separate form, running alongside your script, in the same script! This eliminates the need to paint on the SMART canvas once and for all and the slow/lagginess that induces! This uses form execution methods that haven't been done (from what I can tell) before in Simba or SCAR. Simply put, it;s somewhat multi-threaded :) (well, event-driven really if you want to get technical :p)
I got the idea from somebody around here that said it was "impossible" and "very hard to do" whilst reading a couple of hours ago. :)
It's pretty easy to use! Even look at the following script!
program ProgessTest;
{$i SRL\SRL.simba}
{$i SRL\SRL\Misc\Progress.simba}
var
I: Integer;
procedure ProgressReport;
begin
Progress_Clear;
Progress_Writeln(' /----------------------------------------------------------\');
Progress_Writeln('| Progress Report by Daniel |');
Progress_Writeln('| |');
Progress_Writeln('| We are currently up to number: ' + IntToStr(I) + ' |');
Progress_Writeln(' \----------------------------------------------------------/');
end;
begin
Progress_ScriptName := 'Daniels Test Script!'; // Probably the most important bit of this setup!
Progress_Setup; // Set's up the progress report with default form size (W:650, H: 350). Called ONCE
Progress_LoadBackgroundFromFile(ScriptPath + 'bgprogresstest.bmp'); // Let's have a nice background, shall we? :)
Progress_ChangeInterval(5000); // Update the progress report every 5 seconds
OnProgressUpdate := @ProgressReport; // The procedure to run when above time interval passes.
Progress_Show; // Actually displays the progress report form.
for I := 0 to 20 do // Do whatever code here.
begin // In this case, it's a for..loop.
Writeln(I); { You will notice that ProgessReport() should get called at the same time this is running! }
Wait(500); // Let's not spam shall we. :)
end;
Progress_Close; // Closes the form. Not really necessary if its at the end of the script.
Progress_Unload; // Frees everything to do with the form from memory! Just as above, it isn't really necessary if it's at the end of the script.
end.
Pretty easy, eh? Everything to do with this (except one, the OnProgressUpdate) has a prefix of Progress_, and the names are pretty easy too! So you can't get confused by it :)
Also, here's the actual include (place it in /SRL/SRL/Misc/Progress.simba):
(*
Progress Report Form by Daniel
======
The Progress Report Form include allows the execution of periodic script reports
specified by the user/scripter in a separate window. This include allows the
runtime of a periodic updating form as-well as script execution simultaneously.
If you (the scripter/user) leave everything the
.. contents::
*)
const
DEFAULT_INTERVAL = 300000; { Default timer interval (in milliseconds),
default-untouched is 5 minutes. }
// Theses are just some silly variables you don't need to know :D
var
PF_ProgressForm: TForm;
PF_ProgressForm_Text: TMemo;
PF_ProgressForm_Background: TImage;
PF_ProgressForm_Updater: TTimer;
PF_ProgressClose: Boolean;
(*
OnProgressUpdate
~~~~~~~~~~~
.. code-block:: pascal
var OnProgressUpdate: procedure;
This here is what defines what method the Progress Report Form should call when
the period for an update is due. All you have to do is link it to a procedure
(with no parametres! If you don't know what that is, then don't worry!) See the
example below on how to link a procedure (note the '@' symbol).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
procedure ProgressReport;
begin
end;
begin
OnProgressUpdate := @ProgressReport;
end.
*)
OnProgressUpdate: procedure;
(*
Progress_ScriptName
~~~~~~~~~~~
.. code-block:: pascal
var Progress_ScriptName: String;
What is the name of your script? This is used if you don't want to change the
title of the form later on.
E.g, if you set it to "Daniels Guild Miner", then the title of the Progress
Report Form will be "Daniels Guild Miner - Progress Report".
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ScriptName := 'Daniels Guild Miner';
end.
*)
Progress_ScriptName: String;
procedure ThreadSafeCallNoParams(const ProcName: String); forward;
(*
Rect
~~~~~~~~~~~
.. code-block:: pascal
function Rect(const Left, Top, Right, Bottom: Integer): TRect;
Similar to the Point() and IntToBox() methods. Converts the split up values of
a TRect into a TRect type.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
var
NewRect: TRect;
begin
NewRect := Rect(0, 0, 300, 300);
end.
*)
function Rect(const Left, Top, Right, Bottom: Integer): TRect;
begin
// with..do statements are bad here
Result.Left := Left;
Result.Top := Top;
Result.Right := Right;
Result.Bottom := Bottom;
end;
(*
Progress_SetupEx
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_SetupEx(const Bounds: TRect);
Set's up the Progress Report Form with scripter specified dimensions. This is
useful if the scripter wants to add a larger background image, or wants to display
more text on the screen.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_SetupEx(Rect(0, 0, 300, 300));
end.
*)
procedure Progress_SetupEx(const Bounds: TRect);
var
Params: TVariantArray;
begin
if(Assigned(PF_ProgressForm)) then
Exit;
Params := [Bounds.Left, Bounds.Top, Bounds.Right, Bounds.Bottom];
ThreadSafeCall('UnsafeSetupProgress', Params);
end;
(*
Progress_Setup
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Setup;
Set's up the Progress Report Form with default dimensions of 650x350. This is
suitable for most applications. Use Progress_SetupEx() for a much more customisable
setup.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Setup;
end.
*)
procedure Progress_Setup;
begin
Progress_SetupEx(Rect(0, 0, 650, 350));
end;
(*
Progress_Show
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Show;
Displays the Progress Report Form.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Show;
end.
*)
procedure Progress_Show;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressClose := False;
ThreadSafeCallNoParams('UnsafeShowProgress');
end;
(*
Progress_Close
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Close;
Hides/closes the Progress Report Form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Close;
end.
*)
procedure Progress_Close;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressClose := True;
ThreadSafeCallNoParams('UnSafeCloseProgress');
end;
(*
Progress_Unload
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Unload;
Reverses the effect of SetupEx or Setup. Basically it closes the form (if it's open)
and free's a tiny little bit of RAM. Generally the scripter should not need to call
this. This is automatically run when upon script termination/completeion.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Unload;
end.
*)
procedure Progress_Unload;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
if(not(PF_ProgressClose)) then
Progress_Close;
ThreadSafeCallNoParams('UnsafeUnloadProgress');
end;
(*
Progress_ChangeInterval
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_ChangeInterval(const NewInterval: Cardinal);
Changes the interval between the periodic updates of calling the Progress Report
procedure (in milliseconds, so 1000 is the equivalent of 1 second).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ChangeInterval(5000); // It is now updating every 5 seconds
end.
*)
procedure Progress_ChangeInterval(const NewInterval: Cardinal);
var
Params: TVariantArray;
begin
Params := [NewInterval];
ThreadSafeCall('UnsafeChangeInterval', Params);
end;
(*
Progress_LoadBackgroundFromFile
~~~~~~~~~~~
.. code-block:: pascal
function Progress_LoadBackgroundFromFile(const FileName: AnsiString): Boolean;
Load's a background image from an external bitmap file. Returns True if the background
was successfully set. The image will automatically stretch to the width
and height of the form.
NOTE: It MUST be an image stored as a Windows Bitmap (*.bmp).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_LoadBackgroundFromFile(ScriptPath + 'background.bmp');
end.
*)
function Progress_LoadBackgroundFromFile(const FileName: AnsiString): Boolean;
begin
Result := Lowercase(ExtractFileExt(FileName)) = '.bmp';
if(not(Result)) then
Exit;
PF_ProgressForm_Background.Picture.Bitmap.LoadFromFile(FileName);
end;
(*
Progress_LoadBackground
~~~~~~~~~~~
.. code-block:: pascal
function Progress_LoadBackground(const I: Integer): Boolean;
Load's a background image from a bitmap file loaded by Simba. Returns True if the background
was successfully set. The image will automatically stretch to the width and height
of the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
var
Bmp: Integer;
begin
Bmp := BitmapFromString(650, 350, '...');
Progress_LoadBackground(Bmp);
end.
*)
function Progress_LoadBackground(const I: Integer): Boolean;
var
tempMufasaBitmap: TMufasaBitmap;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
tempMufasaBitmap := GetMufasaBitmap(I);
Result := Assigned(tempMufasaBitmap);
if(not(Result)) then
Exit;
PF_ProgressForm_Background.Picture.Assign(tempMufasaBitmap.ToTBitmap);
tempMufasaBitmap.Free;
tempMufasaBitmap := nil;
end;
(*
Progress_WriteLn
~~~~~~~~~~~
.. code-block:: pascal
function Progress_WriteLn(const V: Variant): Integer;
Send's text to the Progress Report Form to be displayed. Similar to Simba's
Writeln, except it doesn't support automatically displaying arrays. Returns
the line number which the text was printed on.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_WriteLn('Progress Report for Daniel''s Guild Miner: ');
end.
*)
function Progress_WriteLn(const V: Variant): Integer;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
Result := PF_ProgressForm_Text.Lines.Add(V);
// Compensate for those "one-liner" progress report forms.
if(PF_ProgressForm.Height < 78) then
PF_ProgressForm_Text.SelStart := Length(PF_ProgressForm_Text.Text) - 1;
end;
(*
Progress_ModifyLine
~~~~~~~~~~~
.. code-block:: pascal
function Progress_ModifyLine(const V: Variant; const Line: Integer): Boolean;
Replaces a line's text with V. Line is the line number (can be retrieved from
the above mentioned methiod, Progress_Writeln.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ModifyLine('I am replacing the first line!', 0);
end.
*)
function Progress_ModifyLine(const V: Variant; const Line: Integer): Boolean;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
Result := Line < (PF_ProgressForm_Text.Lines.Count);
if(not(Result)) then
Exit;
PF_ProgressForm_Text.Lines.Strings[Line] := V;
end;
(*
Progress_Clear
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Clear;
Erases the entire contents of the text box on the Progress Report Form. Similar
to Simba's ClearDebug().
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Clear;
end.
*)
procedure Progress_Clear;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressForm_Text.Lines.Clear;
end;
(*
Progress_ChangeCaption
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_ChangeCaption(const NewCaption: String);
Changes the title of the Progress Report Form to NewCaption.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ChangeCaption('This is the new title!');
end.
*)
procedure Progress_ChangeCaption(const NewCaption: String);
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressForm.Caption := NewCaption;
end;
{* ******************************************************************************
DO NOT TOUCH, AND *ESPECIALLY* DO NOT CALL ANY METHODS LISTED BELOW HERE.
THEY ARE NAMED 'UNSAFE' FOR A REASON.
Unless you know what you are doing, DON'T TOUCH!
- Regards, Daniel. =)
****************************************************************************** *}
procedure ThreadSafeCallNoParams(const ProcName: String);
var
Params: TVariantArray;
begin
Params := [];
ThreadSafeCall(ProcName, Params);
end;
procedure PF_OnProgressTimer(Sender: TObject);
begin
if(Sender = PF_ProgressForm_Updater) then
OnProgressUpdate();
end;
procedure PF_ProgressCanClose(Sender: TObject; var CanClose: Boolean);
begin
CanClose := PF_ProgressClose;
end;
procedure UnsafeSetupProgress(const Left, Top, Right, Bottom: Integer);
begin
PF_ProgressForm := TForm.Create(nil);
PF_ProgressForm.SetBounds(Left, Top, Right, Bottom);
PF_ProgressForm.Caption := Progress_ScriptName + ' - Progress Report';
PF_ProgressForm.Position := poMainFormCenter;
PF_ProgressForm.BorderStyle := bsSingle; // Non-resizeable, non-maximisable form. Which is what we want.
PF_ProgressForm.OnCloseQuery := @PF_ProgressCanClose;
PF_ProgressForm.FormStyle := fsStayOnTop;
PF_ProgressForm_Text := TMemo.Create(PF_ProgressForm);
PF_ProgressForm_Text.Parent := PF_ProgressForm;
PF_ProgressForm_Text.SetBounds(Left + 20, Top + 20, Right - 40, Bottom - 40);
PF_ProgressForm_Text.Font.Name := 'Courier New';
PF_ProgressForm_Text.Font.Size := 10;
PF_ProgressForm_Text.ReadOnly := True;
PF_ProgressForm_Text.WordWrap := False;
PF_ProgressForm_Updater := TTimer.Create(PF_ProgressForm);
PF_ProgressForm_Updater.Interval := DEFAULT_INTERVAL;
PF_ProgressForm_Updater.OnTimer := @PF_OnProgressTimer;
{PF_ProgressForm_Updater.Enabled := True; }
PF_ProgressForm_Background := TImage.Create(PF_ProgressForm);
PF_ProgressForm_Background.Parent := PF_ProgressForm;
PF_ProgressForm_Background.SetBounds(Left, Top, Right, Bottom);
PF_ProgressForm_Background.Stretch := True;
PF_ProgressForm_Background.SendToBack;
AddOnTerminate('Progress_Unload');
end;
procedure UnsafeUnloadProgress;
begin
{ Form components }
PF_ProgressForm_Background.Free;
PF_ProgressForm_Background := nil;
PF_ProgressForm_Text.Free;
PF_ProgressForm_Text := nil;
PF_ProgressForm_Updater.Free;
PF_ProgressForm_Updater := nil;
{ The actual form itself }
PF_ProgressForm.Free;
PF_ProgressForm := nil;
end;
procedure UnsafeShowProgress;
begin
PF_ProgressForm.Show;
PF_ProgressForm_Updater.Enabled := True;
end;
procedure UnsafeCloseProgress;
begin
PF_ProgressForm.Close;
PF_ProgressForm_Updater.Enabled := False;
end;
// I did this for a reason. I can't exactly recall if setting the interval
// without destroying the component worked or not.
procedure UnsafeChangeInterval(const NewInterval: Cardinal);
var
WasAlreadyEnabled: Boolean; // Rather self-explanatory...
begin
WasAlreadyEnabled := False;
if(Assigned(PF_ProgressForm_Updater)) then
begin
WasAlreadyEnabled := PF_ProgressForm_Updater.Enabled;
PF_ProgressForm_Updater.Free;
PF_ProgressForm_Updater := nil;
end;
PF_ProgressForm_Updater := TTimer.Create(PF_ProgressForm);
PF_ProgressForm_Updater.OnTimer := @PF_OnProgressTimer;
PF_ProgressForm_Updater.Interval := NewInterval;
PF_ProgressForm_Updater.Enabled := WasAlreadyEnabled;
end(*
Progress Report Form by Daniel
======
The Progress Report Form include allows the execution of periodic script reports
specified by the user/scripter in a separate window. This include allows the
runtime of a periodic updating form as-well as script execution simultaneously.
.. contents::
*)
const
DEFAULT_INTERVAL = 300000; { Default timer interval (in milliseconds),
default-untouched is 5 minutes. }
// Theses are just some silly variables you don't need to know :D
var
PF_ProgressForm: TForm;
PF_ProgressForm_Text: TMemo;
PF_ProgressForm_Background: TImage;
PF_ProgressForm_Updater: TTimer;
PF_ProgressClose: Boolean;
(*
OnProgressUpdate
~~~~~~~~~~~
.. code-block:: pascal
var OnProgressUpdate: procedure;
This here is what defines what method the Progress Report Form should call when
the period for an update is due. All you have to do is link it to a procedure
(with no parametres! If you don't know what that is, then don't worry!) See the
example below on how to link a procedure (note the '@' symbol).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
procedure ProgressReport;
begin
end;
begin
OnProgressUpdate := @ProgressReport;
end.
*)
OnProgressUpdate: procedure;
(*
Progress_ScriptName
~~~~~~~~~~~
.. code-block:: pascal
var Progress_ScriptName: String;
What is the name of your script? This is used if you don't want to change the
title of the form later on.
E.g, if you set it to "Daniels Guild Miner", then the title of the Progress
Report Form will be "Daniels Guild Miner - Progress Report".
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ScriptName := 'Daniels Guild Miner';
end.
*)
Progress_ScriptName: String;
procedure ThreadSafeCallNoParams(const ProcName: String); forward;
(*
Rect
~~~~~~~~~~~
.. code-block:: pascal
function Rect(const Left, Top, Right, Bottom: Integer): TRect;
Similar to the Point() and IntToBox() methods. Converts the split up values of
a TRect into a TRect type.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
var
NewRect: TRect;
begin
NewRect := Rect(0, 0, 300, 300);
end.
*)
function Rect(const Left, Top, Right, Bottom: Integer): TRect;
begin
// with..do statements are bad here
Result.Left := Left;
Result.Top := Top;
Result.Right := Right;
Result.Bottom := Bottom;
end;
(*
Progress_SetupEx
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_SetupEx(const Bounds: TRect);
Set's up the Progress Report Form with scripter specified dimensions. This is
useful if the scripter wants to add a larger background image, or wants to display
more text on the screen.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_SetupEx(Rect(0, 0, 300, 300));
end.
*)
procedure Progress_SetupEx(const Bounds: TRect);
var
Params: TVariantArray;
begin
if(Assigned(PF_ProgressForm)) then
Exit;
Params := [Bounds.Left, Bounds.Top, Bounds.Right, Bounds.Bottom];
ThreadSafeCall('UnsafeSetupProgress', Params);
end;
(*
Progress_Setup
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Setup;
Set's up the Progress Report Form with default dimensions of 650x350. This is
suitable for most applications. Use Progress_SetupEx() for a much more customisable
setup.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Setup;
end.
*)
procedure Progress_Setup;
begin
Progress_SetupEx(Rect(0, 0, 650, 350));
end;
(*
Progress_Show
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Show;
Displays the Progress Report Form.
NOTE: You MUST call a setup procedure BEFORE you display the form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Show;
end.
*)
procedure Progress_Show;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressClose := False;
ThreadSafeCallNoParams('UnsafeShowProgress');
end;
(*
Progress_Close
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Close;
Hides/closes the Progress Report Form.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Close;
end.
*)
procedure Progress_Close;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressClose := True;
ThreadSafeCallNoParams('UnSafeCloseProgress');
end;
(*
Progress_Unload
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Unload;
Reverses the effect of SetupEx or Setup. Basically it closes the form (if it's open)
and free's a tiny little bit of RAM. Generally the scripter should not need to call
this. This is automatically run when upon script termination/completeion.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Unload;
end.
*)
procedure Progress_Unload;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
if(not(PF_ProgressClose)) then
Progress_Close;
ThreadSafeCallNoParams('UnsafeUnloadProgress');
end;
(*
Progress_ChangeInterval
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_ChangeInterval(const NewInterval: Cardinal);
Changes the interval between the periodic updates of calling the Progress Report
procedure (in milliseconds, so 1000 is the equivalent of 1 second).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ChangeInterval(5000); // It is now updating every 5 seconds
end.
*)
procedure Progress_ChangeInterval(const NewInterval: Cardinal);
var
Params: TVariantArray;
begin
Params := [NewInterval];
ThreadSafeCall('UnsafeChangeInterval', Params);
end;
(*
Progress_LoadBackgroundFromFile
~~~~~~~~~~~
.. code-block:: pascal
function Progress_LoadBackgroundFromFile(const FileName: AnsiString): Boolean;
Load's a background image from an external bitmap file. Returns True if the background
was successfully set.
NOTE: It MUST be an image stored as a Windows Bitmap (*.bmp).
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_LoadBackgroundFromFile(ScriptPath + 'background.bmp');
end.
*)
function Progress_LoadBackgroundFromFile(const FileName: AnsiString): Boolean;
begin
Result := Lowercase(ExtractFileExt(FileName)) = '.bmp';
if(not(Result)) then
Exit;
PF_ProgressForm_Background.Picture.Bitmap.LoadFromFile(FileName);
end;
(*
Progress_LoadBackground
~~~~~~~~~~~
.. code-block:: pascal
function Progress_LoadBackground(const I: Integer): Boolean;
Load's a background image from a bitmap file loaded by Simba. Returns True if the background
was successfully set.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
var
Bmp: Integer;
begin
Bmp := BitmapFromString(650, 350, '...');
Progress_LoadBackground(Bmp);
end.
*)
function Progress_LoadBackground(const I: Integer): Boolean;
var
tempMufasaBitmap: TMufasaBitmap;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
tempMufasaBitmap := GetMufasaBitmap(I);
Result := Assigned(tempMufasaBitmap);
if(not(Result)) then
Exit;
PF_ProgressForm_Background.Picture.Assign(tempMufasaBitmap.ToTBitmap);
tempMufasaBitmap.Free;
tempMufasaBitmap := nil;
end;
(*
Progress_WriteLn
~~~~~~~~~~~
.. code-block:: pascal
function Progress_WriteLn(const V: Variant): Integer;
Send's text to the Progress Report Form to be displayed. Similar to Simba's
Writeln, except it doesn't support automatically displaying arrays. Returns
the line number which the text was printed on.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_WriteLn('Progress Report for Daniel''s Guild Miner: ');
end.
*)
function Progress_WriteLn(const V: Variant): Integer;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
Result := PF_ProgressForm_Text.Lines.Add(V);
// Compensate for those "one-liner" progress report forms.
if(PF_ProgressForm.Height < 78) then
PF_ProgressForm_Text.SelStart := Length(PF_ProgressForm_Text.Text) - 1;
end;
(*
Progress_ModifyLine
~~~~~~~~~~~
.. code-block:: pascal
function Progress_ModifyLine(const V: Variant; const Line: Integer): Boolean;
Replaces a line's text with V. Line is the line number (can be retrieved from
the above mentioned methiod, Progress_Writeln.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ModifyLine('I am replacing the first line!', 0);
end.
*)
function Progress_ModifyLine(const V: Variant; const Line: Integer): Boolean;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
Result := Line < (PF_ProgressForm_Text.Lines.Count);
if(not(Result)) then
Exit;
PF_ProgressForm_Text.Lines.Strings[Line] := V;
end;
(*
Progress_Clear
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_Clear;
Erases the entire contents of the text box on the Progress Report Form. Similar
to Simba's ClearDebug().
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_Clear;
end.
*)
procedure Progress_Clear;
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressForm_Text.Lines.Clear;
end;
(*
Progress_ChangeCaption
~~~~~~~~~~~
.. code-block:: pascal
procedure Progress_ChangeCaption(const NewCaption: String);
Changes the title of the Progress Report Form to NewCaption.
.. note::
Author: Daniel
Date Added: 9/01/2012
Example:
.. code-block:: pascal
begin
Progress_ChangeCaption('This is the new title!');
end.
*)
procedure Progress_ChangeCaption(const NewCaption: String);
begin
if(not(Assigned(PF_ProgressForm))) then
Exit;
PF_ProgressForm.Caption := NewCaption;
end;
{* ******************************************************************************
DO NOT TOUCH, AND *ESPECIALLY* DO NOT CALL ANY METHODS LISTED BELOW HERE.
THEY ARE NAMED 'UNSAFE' FOR A REASON.
Unless you know what you are doing, DON'T TOUCH!
- Regards, Daniel. =)
****************************************************************************** *}
procedure ThreadSafeCallNoParams(const ProcName: String);
var
Params: TVariantArray;
begin
Params := [];
ThreadSafeCall(ProcName, Params);
end;
procedure PF_OnProgressTimer(Sender: TObject);
begin
if(Sender = PF_ProgressForm_Updater) then
try
OnProgressUpdate();
except
srl_Warn('PF_OnProgressTimer', 'Unable to call OnProgressUpdate. Exception raised.', warn_AllVersions);
end;
end;
procedure PF_ProgressCanClose(Sender: TObject; var CanClose: Boolean);
begin
CanClose := PF_ProgressClose;
end;
procedure UnsafeSetupProgress(const Left, Top, Right, Bottom: Integer);
begin
PF_ProgressForm := TForm.Create(nil);
PF_ProgressForm.SetBounds(Left, Top, Right, Bottom);
PF_ProgressForm.Caption := Progress_ScriptName + ' - Progress Report';
PF_ProgressForm.Position := poMainFormCenter;
PF_ProgressForm.BorderStyle := bsSingle; // Non-resizeable, non-maximisable form. Which is what we want.
PF_ProgressForm.OnCloseQuery := @PF_ProgressCanClose;
PF_ProgressForm.FormStyle := fsStayOnTop;
PF_ProgressForm_Text := TMemo.Create(PF_ProgressForm);
PF_ProgressForm_Text.Parent := PF_ProgressForm;
PF_ProgressForm_Text.SetBounds(Left + 20, Top + 20, Right - 40, Bottom - 40);
PF_ProgressForm_Text.Font.Name := 'Courier New';
PF_ProgressForm_Text.Font.Size := 10;
PF_ProgressForm_Text.ReadOnly := True;
PF_ProgressForm_Text.WordWrap := False;
PF_ProgressForm_Updater := TTimer.Create(PF_ProgressForm);
PF_ProgressForm_Updater.Interval := DEFAULT_INTERVAL;
PF_ProgressForm_Updater.OnTimer := @PF_OnProgressTimer;
{PF_ProgressForm_Updater.Enabled := True; }
PF_ProgressForm_Background := TImage.Create(PF_ProgressForm);
PF_ProgressForm_Background.Parent := PF_ProgressForm;
PF_ProgressForm_Background.SetBounds(Left, Top, Right, Bottom);
PF_ProgressForm_Background.Stretch := True;
PF_ProgressForm_Background.SendToBack;
AddOnTerminate('Progress_Unload');
end;
procedure UnsafeUnloadProgress;
begin
{ Form components }
PF_ProgressForm_Background.Free;
PF_ProgressForm_Background := nil;
PF_ProgressForm_Text.Free;
PF_ProgressForm_Text := nil;
PF_ProgressForm_Updater.Free;
PF_ProgressForm_Updater := nil;
{ The actual form itself }
PF_ProgressForm.Free;
PF_ProgressForm := nil;
end;
procedure UnsafeShowProgress;
begin
PF_ProgressForm.Show;
PF_ProgressForm_Updater.Enabled := True;
end;
procedure UnsafeCloseProgress;
begin
PF_ProgressForm.Close;
PF_ProgressForm_Updater.Enabled := False;
end;
// I did this for a reason. I can't exactly recall if setting the interval
// without destroying the component worked or not.
procedure UnsafeChangeInterval(const NewInterval: Cardinal);
var
WasAlreadyEnabled: Boolean; // Rather self-explanatory...
begin
WasAlreadyEnabled := False;
if(Assigned(PF_ProgressForm_Updater)) then
begin
WasAlreadyEnabled := PF_ProgressForm_Updater.Enabled;
PF_ProgressForm_Updater.Free;
PF_ProgressForm_Updater := nil;
end;
PF_ProgressForm_Updater := TTimer.Create(PF_ProgressForm);
PF_ProgressForm_Updater.OnTimer := @PF_OnProgressTimer;
PF_ProgressForm_Updater.Interval := NewInterval;
PF_ProgressForm_Updater.Enabled := WasAlreadyEnabled;
end;
And damn you Kyle Undefined! This made me stay awake until 4am (couple of hours after you told me what you did to help you "sleep")! :p
