Page 1 of 1

"Hello World"

PostPosted: Fri Oct 15, 2010 2:54 pm
by Mark F. Madura
Code: Select all{
  DCAL program Hello_World is intended to be a simple introduction to
  Re-entrant State Machines as they pertain to DCAL for Delphi programming.
  In this example the Re-entrant State Machine is documented in order to
  illustrate the fundamental structure of a DataCAD macro.

  By definition a state machine is a program that stores the status of something
  at a given time and can operate on input to change the status and/or cause an
  action or output to take place for any given change.

  Programmers originally implemented a 're-entrant' state machine in DataCAD
  to make it possible to stack commands.  For example, if you're in the middle of
  one command such as drawing a line, you can press a keyboard interrupt such as
  [/] which will interrupt the line drawing command and bring you to the zoom
  command.  When you exit the zoom command, the re-entrant state machine brings
  you back to the previous command on the stack; drawing a line.

  A hotkey, on the otherhand, breaks out of the current command, clears the
  command stack, and brings you to a new command.  For example, if you're drawing
  a line and press the [C] key, DataCAD will 'break' out of the line command and
  bring you to the copy command.

  There are four main sections within DataCAD's state machine.

  Section 1: AlSize
  This is where DataCAD's state machine allocates memory for your local variables.

  Section 2: Afirst
  This is where you initialize the local state and other variables.  Tasks you
  define here will only be performed once.

  Section 3: Aagain
  This is where DataCAD returns after it has performed an action for you.  The
  action variable will be equal to Aagain until you set the result to XDone.

  Section 4: Alast
  If your macro has been interrupted by user action such as pressing a hotkey,
  DataCAD will set the action to Alast to give you the opportunity to clean up any
  temporary data before exiting to the new command.
}

library Hello_World;

uses
  // Sharemem, { Do not use. All DataCAD parameters are limited to short strings}
  Dialogs,

  //DCAL for Delphi Header Files
  UConstants in '..\Header Files\UConstants.pas',
  UInterfaces in '..\Header Files\UInterfaces.pas',
  UInterfacesRecords in '..\Header Files\UInterfacesRecords.pas',
  URecords in '..\Header Files\URecords.pas',
  UVariables in '..\Header Files\UVariables.pas';

{$E dmx}  // dmx is the extension for DCAL Dll's

// The values stored in the records you define here will be rememberd
// between dispatcher calls because they are pushed onto the command stack
type
  HelloL = record
    state: asint;
    case byte of
      0:
        (getp: getpointArg);
  end;

  PHelloL = ^HelloL;

// Main Function (Re-entrant State Machine)
function hello_world_main(act: action; pl, pargs: Pointer): wantType;
// The values stored in variables you define here will not be retained
// between dispatcher calls because they are not pushed onto the stack
var
  retval: asint;
  l: PHelloL;
begin
  l := PHelloL(pl);

  { Section 3: Aagain - Return to menus and wait for input }
  if act = Aagain then begin // Re-entrant section
    case l.state of
      1: begin
          // If a key was pressed or a menu button was selected...
          if l.getp.Result = res_escape then begin
            case l.getp.key of
              f1:
                l.state := 2; { Say Hello }
              s0:
                l.state := 0; { Exit }
            end;
          end;
        end;
      2:
        l.state := 1;
    else
      l.state := 0;
    end;
  end;

  { Section 2: Afirst - Tasks to perform only once }
  if act = Afirst then begin // Initialize local state and other variables
    wrterr('Hello World Macro - Version 1.0');
    l.state := 1;
  end

  { Section 4: Alast - If your macro has been interrupted by user action }
  else if act = Alast then begin
    // If you're going to get blown off the stack...
    // (i.e.) the user pressed a hotkey,
    // then this is your last chance to clean up temporary data.
  end

  { Section 1: AlSize - Allocate memory on stack for local variables }
  else if act = AlSize then begin
    SetLocalSize(sizeof(l^));
  end;

  if act <> AlSize then begin { Action section - Invoke the Dispatcher }
    case l.state of
      1: begin
          wrtlvl('Hello'); // Set Menu Title
          lblsinit;
          lblset(1, 'Say Hello', 'Select this button to say "Hello"');
          lblset(20, 'Exit', '"Goodbye"');
          lblson;
          getpoint(l.getp, retval);
        end;
      2: begin
          wrtmsg('Hello World!', true);
          MessageDlg('Hello World!', mtConfirmation, [mbOK], 0);
          callNone(retval);  {  You have to tell the dispatcher to do something.
                                In this case, tell the dispatcher to do nothing. }
        end;
    else
      retval := XDone; // Don't go back to Aagain
    end;
  end;
  Result := retval;
end;
// End of Main Function (Re-entrant State Machine)

function Main(dcalstate: asint; act: action; pl, pargs: Pointer)
  : wantType; stdcall;
begin
  case dcalstate of
    XDcalStateBegin:
      Result := hello_world_main(act, pl, pargs);
  else
    Result := XDone; { Necessary }
  end;
end;

exports
  Main; { This is the entry function that will be called by DataCAD.
  All DCAL Dlls will have this function. }

begin

end.