MODULE WMShapes;
IMPORT
Strings, XML, WMRectangles, WMGraphics, WMGraphicUtilities, WMProperties, WMComponents, Math, KernelLog;
TYPE
Line* = OBJECT(WMComponents.VisualComponent)
VAR
color- : WMProperties.ColorProperty;
colorI : LONGINT;
isVertical- : WMProperties.BooleanProperty;
isVerticalI : BOOLEAN;
start-, end-: WMProperties.PointProperty;
startI, endI: WMGraphics.Point2d;
arrowAtStart-, arrowAtEnd-:WMProperties.BooleanProperty;
arrowAtStartI, arrowAtEndI: BOOLEAN;
PROCEDURE &Init*;
BEGIN
Init^;
SetGenerator("WMShapes.GenLine");
SetNameAsString(StrLine);
NEW(color, NIL, StrColor, StrLineColorDescription); properties.Add(color);
color.Set(WMGraphics.Black); colorI := color.Get();
NEW(isVertical, NIL, StrIsVertical, StrIsVerticalDescription); properties.Add(isVertical);
isVertical.Set(FALSE); isVerticalI := isVertical.Get();
NEW(start, NIL, StrStart, StrStartDescription); properties.Add(start);
start.SetCoordinate(0,0); startI := start.Get();
NEW(end, NIL, StrEnd, StrEndDescription); properties.Add(end);
end.SetCoordinate(100,100); endI := end.Get();
NEW(arrowAtStart, NIL, StrArrowStart, StrArrowStartDescription); properties.Add(arrowAtStart);
arrowAtStart.Set(FALSE); arrowAtStartI := arrowAtStart.Get();
NEW(arrowAtEnd, NIL, StrArrowEnd, StrArrowEndDescription); properties.Add(arrowAtEnd);
arrowAtEnd.Set(TRUE); arrowAtEndI := arrowAtEnd.Get();
PropertyChanged(SELF, start);
END Init;
PROCEDURE PropertyChanged*(sender, property : ANY);
VAR dx, dy :LONGINT; rect, rect0: WMRectangles.Rectangle;
BEGIN
IF (property = color) THEN colorI := color.Get(); Invalidate;
ELSIF (property = isVertical) THEN isVerticalI := isVertical.Get(); Invalidate;
ELSIF (property = start) OR (property = end) THEN
rect0:=bounds.Get(); startI := start.Get(); endI := end.Get();
rect:=WMRectangles.MakeRect(MIN(startI.x,endI.x)+rect0.l-5, MIN(startI.y,endI.y)+rect0.t-5, MAX(startI.x, endI.x)+rect0.l+5, MAX(startI.y,endI.y)+rect0.t+5);
dx:=rect.l - rect0.l;
dy:=rect.t - rect0.t;
startI.x:=startI.x-dx; endI.x:=endI.x-dx;
startI.y:=startI.y-dy; endI.y:=endI.y-dy;
IF ~WMRectangles.IsEqual(rect,rect0) THEN bounds.Set(rect); END;
start.Set(startI);
end.Set(endI);
Invalidate;
ELSIF (property = arrowAtStart) THEN arrowAtStartI := arrowAtStart.Get(); Invalidate;
ELSIF (property = arrowAtEnd) THEN arrowAtEndI := arrowAtEnd.Get(); Invalidate;
ELSE PropertyChanged^(sender, property);
END;
END PropertyChanged;
PROCEDURE Set*(x0,y0, x1, y1: LONGINT);
VAR rect:WMRectangles.Rectangle; changed:BOOLEAN;
BEGIN
rect:=bounds.Get();
changed:=FALSE;
IF (x0 # rect.l + startI.x) OR (y0#rect.t+startI.y) THEN start.SetCoordinate(x0-rect.l, y0-rect.t); changed:=TRUE END;
IF (x1 # rect.l + endI.x) OR (y1#rect.t+endI.y) THEN end.SetCoordinate(x1-rect.l, y1-rect.t); changed:=TRUE END;
IF changed THEN PropertyChanged(SELF, start); PropertyChanged(SELF, end) END;
END Set;
PROCEDURE IsHit*(x, y: LONGINT): BOOLEAN;
VAR r: WMRectangles.Rectangle; X0,Y0, X1,Y1: LONGINT; hit:BOOLEAN;
BEGIN
IF ~visible.Get() THEN hit:= FALSE
ELSE
r:=GetClientRect();
X0:=startI.x+r.l; Y0:=startI.y+r.t;
X1:=endI.x+r.l; Y1:=endI.y+r.t;
IF X0=X1 THEN hit:=WMRectangles.PointInRect(x, y, r) & (2>ABS(x-X0))
ELSIF Y0=Y1 THEN hit:=WMRectangles.PointInRect(x, y, r) & (2>ABS(y-Y0))
ELSE hit:= WMRectangles.PointInRect(x, y, r) & (2>ABS((y-Y0) - ((x-X0)*(Y1-Y0)/(X1-X0))))
END;
END;
RETURN hit;
END IsHit;
PROCEDURE SetArrowheads*(arrows:SET);
BEGIN
IF (0 IN arrows)#arrowAtStartI THEN arrowAtStart.Set(0 IN arrows); PropertyChanged(SELF, arrowAtStart); END;
IF (1 IN arrows)#arrowAtEndI THEN arrowAtEnd.Set(1 IN arrows); PropertyChanged(SELF, arrowAtEnd); END;
END SetArrowheads;
PROCEDURE DrawBackground*(canvas : WMGraphics.Canvas);
CONST pi=3.1516; headscale= 0.25;
VAR alpha: REAL;
dx,dy: LONGINT;
size:LONGINT; head: LONGREAL;
BEGIN
DrawBackground^(canvas);
IF (colorI # 0) THEN
dx:=endI.x-startI.x; dy:=endI.y-startI.y;
alpha:=arctan2(dx,dy);
size:= 40;
head:=size * headscale ;
canvas.Line(startI.x, startI.y, endI.x, endI.y, colorI, WMGraphics.ModeSrcOverDst);
IF arrowAtEndI THEN
canvas.Line(endI.x,endI.y, endI.x - ENTIER(0.5+head * Math.cos(alpha + pi/8)), endI.y - ENTIER(0.5+head * Math.sin(alpha + pi/8)), colorI, WMGraphics.ModeSrcOverDst);
canvas.Line(endI.x,endI.y, endI.x - ENTIER(0.5+head * Math.cos(alpha - pi/8)), endI.y - ENTIER(0.5+head * Math.sin(alpha - pi/8)), colorI, WMGraphics.ModeSrcOverDst);
END;
IF arrowAtStartI THEN
canvas.Line(startI.x,startI.y, startI.x + ENTIER(0.5+head * Math.cos(alpha + pi/8)), startI.y + ENTIER(0.5+head * Math.sin(alpha + pi/8)), colorI, WMGraphics.ModeSrcOverDst);
canvas.Line(startI.x,startI.y, startI.x + ENTIER(0.5+head * Math.cos(alpha - pi/8)), startI.y + ENTIER(0.5+head * Math.sin(alpha - pi/8)), colorI, WMGraphics.ModeSrcOverDst);
END
END;
END DrawBackground;
END Line;
TYPE
Rectangle* = OBJECT(WMComponents.VisualComponent)
VAR
clBorder- : WMProperties.ColorProperty;
clBorderI : LONGINT;
PROCEDURE &Init;
BEGIN
Init^;
SetGenerator("WMShapes.GenRectangle");
SetNameAsString(StrRectangle);
NEW(clBorder, NIL, StrClBorder, StrClBorderDescription); properties.Add(clBorder);
clBorder.Set(WMGraphics.Black); clBorderI := clBorder.Get();
END Init;
PROCEDURE PropertyChanged(sender, property : ANY);
BEGIN
IF (property = clBorder) THEN
clBorderI := clBorder.Get();
Invalidate;
ELSE
PropertyChanged^(sender, property);
END;
END PropertyChanged;
PROCEDURE DrawBackground(canvas : WMGraphics.Canvas);
VAR rect : WMRectangles.Rectangle;
BEGIN
DrawBackground^(canvas);
IF (clBorderI # 0) THEN
rect := GetClientRect();
WMGraphicUtilities.DrawRect(canvas, rect, clBorderI, WMGraphics.ModeSrcOverDst);
END;
END DrawBackground;
END Rectangle;
TYPE
Circle* = OBJECT(WMComponents.VisualComponent)
VAR
color : WMProperties.ColorProperty;
colorI : LONGINT;
PROCEDURE &Init;
BEGIN
Init^;
SetGenerator("WMShapes.GenCircle");
SetNameAsString(StrCircle);
NEW(color, NIL, Strings.NewString("Color"), Strings.NewString("Color")); properties.Add(color);
color.Set(WMGraphics.Black); colorI := color.Get();
END Init;
PROCEDURE PropertyChanged(sender, property : ANY);
BEGIN
IF (property = color) THEN
colorI := color.Get();
Invalidate;
ELSE
PropertyChanged^(sender, property);
END;
END PropertyChanged;
PROCEDURE DrawBackground(canvas : WMGraphics.Canvas);
VAR rect : WMRectangles.Rectangle; radius : LONGINT;
BEGIN
DrawBackground^(canvas);
IF (colorI # 0) THEN
rect := bounds.Get();
canvas.SetColor(colorI);
radius := Strings.Min((rect.r - rect.l) DIV 2, (rect.b - rect.t) DIV 2) - 1;
WMGraphicUtilities.Circle(canvas, (rect.r - rect.l) DIV 2, (rect.b - rect.t) DIV 2, radius);
END;
END DrawBackground;
END Circle;
TYPE
Ellipse* = OBJECT(WMComponents.VisualComponent)
VAR
color : WMProperties.ColorProperty;
colorI : LONGINT;
PROCEDURE &Init;
BEGIN
Init^;
SetGenerator("WMShapes.GenEllipse");
SetNameAsString(StrEllipse);
NEW(color, NIL, StrColor, StrColorDescription);
color.Set(WMGraphics.Black); colorI := color.Get();
END Init;
PROCEDURE PropertyChanged(sender, property : ANY);
BEGIN
IF (property = color) THEN
colorI := color.Get();
Invalidate;
ELSE
PropertyChanged^(sender, property);
END;
END PropertyChanged;
PROCEDURE DrawBackground(canvas : WMGraphics.Canvas);
VAR rect : WMRectangles.Rectangle;
BEGIN
DrawBackground^(canvas);
IF (colorI # 0) THEN
rect := bounds.Get();
canvas.SetColor(colorI);
WMGraphicUtilities.Ellipse(canvas, (rect.r - rect.l) DIV 2, (rect.b - rect.t) DIV 2, (rect.r - rect.l) DIV 2 - 1, (rect.b - rect.t) DIV 2 - 1);
END;
END DrawBackground;
END Ellipse;
VAR
StrLine, StrRectangle, StrCircle, StrEllipse : Strings.String;
StrClBorder, StrClBorderDescription, StrColor, StrColorDescription, StrLineColorDescription,
StrIsVertical, StrIsVerticalDescription,
StrStart,StrEnd,StrArrowStart, StrArrowEnd,
StrStartDescription, StrEndDescription, StrArrowStartDescription,StrArrowEndDescription: Strings.String;
PROCEDURE GenLine*() : XML.Element;
VAR line : Line;
BEGIN
NEW(line); RETURN line;
END GenLine;
PROCEDURE GenRectangle*() : XML.Element;
VAR rectangle : Rectangle;
BEGIN
NEW(rectangle); RETURN rectangle;
END GenRectangle;
PROCEDURE GenCircle*() : XML.Element;
VAR circle : Circle;
BEGIN
NEW(circle); RETURN circle;
END GenCircle;
PROCEDURE GenEllipse*() : XML.Element;
VAR ellipse : Ellipse;
BEGIN
NEW(ellipse); RETURN ellipse;
END GenEllipse;
PROCEDURE InitStrings;
BEGIN
StrLine := Strings.NewString("Line");
StrRectangle := Strings.NewString("StrRectangle");
StrCircle := Strings.NewString("StrCircle");
StrEllipse := Strings.NewString("StrEllipse");
StrClBorder := Strings.NewString("ClBorder");
StrClBorderDescription := Strings.NewString("Border color");
StrColor := Strings.NewString("Color");
StrColorDescription := Strings.NewString("Color");
StrLineColorDescription := Strings.NewString("Color of line");
StrStart := Strings.NewString("LineStart");
StrStartDescription := Strings.NewString("start point of line");
StrEnd := Strings.NewString("LineEnd");
StrEndDescription := Strings.NewString("end point of line");
StrArrowStart := Strings.NewString("ArrowAtStart");
StrArrowStartDescription := Strings.NewString("arrows at start of line ?");
StrArrowEnd := Strings.NewString("ArrowAtEnd");
StrArrowEndDescription := Strings.NewString("arrows at end of line ?");
StrIsVertical := Strings.NewString("IsVertical");
StrIsVerticalDescription := Strings.NewString("Horizontal or vertical line?");
END InitStrings;
PROCEDURE arctan2(x,y: REAL): REAL;
BEGIN
IF (x>0) & (y>=0) THEN RETURN Math.arctan(y/x)
ELSIF (x>0) & (y<0) THEN RETURN Math.arctan(y/x)+2*Math.pi
ELSIF x<0 THEN RETURN Math.arctan(y/x)+Math.pi
ELSIF (x=0) & (y>0) THEN RETURN Math.pi/2
ELSIF (x=0) & (y<0) THEN RETURN 3*Math.pi/2
ELSE RETURN 0
END
END arctan2;
BEGIN
InitStrings;
END WMShapes.
SystemTools.FreeDownTo WMShapes ~