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.
-
3I haven't touched Delphi in ages, but it shouldn't be (too) hard to embed Lua in it. (also: matrix44.de/lua)yannis– yannis2012年10月31日 03:53:02 +00:00Commented Oct 31, 2012 at 3:53
-
I used the JVCL Pascal scripting engine, and combined it with FlexGraphics component: flex-graphics.comWarren P– Warren P2015年10月28日 20:38:03 +00:00Commented Oct 28, 2015 at 20:38
2 Answers 2
Have a look at DWS. It's essentially Delphi scripting in Delphi. (Or fairly close. It's its own dialect of Object Pascal, but the author's done an impressive job of it.)
-
Looks promising, if I can replicate the
TCanvas
object in this engine, and synchronize every call/property, I would be set.Jerry Dodge– Jerry Dodge2012年10月31日 04:42:51 +00:00Commented Oct 31, 2012 at 4:42 -
@Jerry: Look at DWS's external units. You can import native objects into DWS with them. It's a bit clumsier than it probably should be, because the author wants a "thick wrapper" around native objects to ensure scripts can be aborted without compromising memory safety, but it can be done.Mason Wheeler– Mason Wheeler2012年10月31日 16:18:58 +00:00Commented Oct 31, 2012 at 16:18
Lua integration?
Lua is language designed for embedding (can be run standalone too)
High speed like in interpreter class, good controlled RAM use. Very good integration with C/C++ Borland too (i haven't legal Delphi to check), few Delphi integrations exist.