Scripting custom drawing in Delphi application with IF/THEN/ELSE statements?
- by Jerry Dodge
I'm building a Delphi application which displays a blueprint of a building, including doors, windows, wiring, lighting, outlets, switches, etc. I have implemented a very lightweight script of my own to call drawing commands to the canvas, which is loaded from a database. For example, one command is ELP 1110,1110,1290,1290,3,8388608 which draws an ellipse, parameters are 1110x1110 to 1290x1290 with pen width of 3 and the color 8388608 converted from an integer to a TColor.
What I'm now doing is implementing objects with common drawing routines, and I'd like to use my scripting engine, but this calls for IF/THEN/ELSE statements and such. For example, when I'm drawing a light, if the light is turned on, I'd like to draw it yellow, but if it's off, I'd like to draw it gray. My current scripting engine has no recognition of such statements. It just accepts simple drawing commands which correspond with TCanvas methods.
Here's the procedure I've developed (incomplete) for executing a drawing command on a canvas:
function DrawCommand(const Cmd: String; var Canvas: TCanvas): Boolean;
type
TSingleArray = array of Single;
var
Br: TBrush;
Pn: TPen;
X: Integer;
P: Integer;
L: String;
Inst: String;
T: String;
Nums: TSingleArray;
begin
Result:= False;
Br:= Canvas.Brush;
Pn:= Canvas.Pen;
if Assigned(Canvas) then begin
if Length(Cmd) > 5 then begin
L:= UpperCase(Cmd);
if Pos(' ', L)> 0 then begin
Inst:= Copy(L, 1, Pos(' ', L) - 1);
Delete(L, 1, Pos(' ', L));
L:= L + ',';
SetLength(Nums, 0);
X:= 0;
while Pos(',', L) > 0 do begin
P:= Pos(',', L);
T:= Copy(L, 1, P - 1);
Delete(L, 1, P);
SetLength(Nums, X + 1);
Nums[X]:= StrToFloatDef(T, 0);
Inc(X);
end;
Br.Style:= bsClear;
Pn.Style:= psSolid;
Pn.Color:= clBlack;
if Inst = 'LIN' then begin
Pn.Width:= Trunc(Nums[4]);
if Length(Nums) > 5 then begin
Br.Style:= bsSolid;
Br.Color:= Trunc(Nums[5]);
end;
Canvas.MoveTo(Trunc(Nums[0]), Trunc(Nums[1]));
Canvas.LineTo(Trunc(Nums[2]), Trunc(Nums[3]));
Result:= True;
end else
if Inst = 'ELP' then begin
Pn.Width:= Trunc(Nums[4]);
if Length(Nums) > 5 then begin
Br.Style:= bsSolid;
Br.Color:= Trunc(Nums[5]);
end;
Canvas.Ellipse(Trunc(Nums[0]),Trunc(Nums[1]),Trunc(Nums[2]),Trunc(Nums[3]));
Result:= True;
end else
if Inst = 'ARC' then begin
Pn.Width:= Trunc(Nums[8]);
Canvas.Arc(Trunc(Nums[0]),Trunc(Nums[1]),Trunc(Nums[2]),Trunc(Nums[3]),
Trunc(Nums[4]),Trunc(Nums[5]),Trunc(Nums[6]),Trunc(Nums[7]));
Result:= True;
end else
if Inst = 'TXT' then begin
Canvas.Font.Size:= Trunc(Nums[2]);
Br.Style:= bsClear;
Pn.Style:= psSolid;
T:= Cmd;
Delete(T, 1, Pos(' ', T));
Delete(T, 1, Pos(',', T));
Delete(T, 1, Pos(',', T));
Delete(T, 1, Pos(',', T));
Canvas.TextOut(Trunc(Nums[0]), Trunc(Nums[1]), T);
Result:= True;
end;
end else begin
//No space found, not a valid command
end;
end;
end;
end;
What I'd like to know is what's a good lightweight third-party scripting engine I could use to accomplish this? I would hate to implement parsing of IF, THEN, ELSE, END, IFELSE, IFEND, and all those necessary commands. I need simply the ability to tell the scripting engine if certain properties meet certain conditions, it needs to draw the object a certain way.
The light example above is only one scenario, but the same solution needs to also be applicable to other scenarios, such as a door being open or closed, locked or unlocked, and draw it a different way accordingly. This needs to be implemented in the object script drawing level. I can't hard-code any of these scripting/drawing rules, the drawing needs to be controlled based on the current state of the object, and I may also wish to draw a light a certain shade or darkness depending on how dimmed the light is.