The DataCAD Developer Network (DDN) is an online resource for information and support for DCAL® (DataCAD Applications Language) developers as well as anyone interested in creating fonts, toolbars, hatch patterns, or linetypes for use in DataCAD.

Moderator: pjdixit

#50687 by Mark F. Madura
Fri Oct 15, 2010 2:54 pm
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.

Who is online

Users browsing this forum: No registered users and 2 guests

About DataCAD Forum

The DataCAD Forum is a FREE online community we provide to enhance your experience with DataCAD.

We hope you'll visit often to get answers, share ideas, and interact with other DataCAD users around the world.

DataCAD

Software for AEC Professionals Since 1984