unit frmMain;
interface
uses
Winapi.Windows,
Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
Vcl.Graphics,
Vcl.Controls,
Vcl.Forms,
Vcl.Dialogs,
Vcl.ExtCtrls, acPNG;
const
DOT_RADIUS = 8;
maxXDots = 3;
maxYDots = 3;
MOUSE_SLACK = 16;
type
TPointIdx =
Record
XIdx: Integer;
YIdx: Integer;
End;
TDot =
Record
Pos: TPoint;
Bounds: TRect;
Selected: Boolean;
LinkTo: TPointIdx;
End;
TForm1 =
class(TForm)
PB: TPaintBox;
procedure FormCreate(Sender: TObject);
procedure PBMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure PBMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
procedure PBMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure PBPaint(Sender: TObject);
private
fDots:
Array[0..maxXDots-1,0..maxYDots-1]
Of TDot;
fDown: Boolean;
fPO: TPointIdx;
fCurPos: TPoint;
procedure CalcDotPositions;
procedure ResetDotSelection;
function MouseNearDots(X,Y: Integer;
Var DXIdx, DYIdx: Integer): Boolean;
function HasLinkTo(ADot: TDot): Boolean;
public
{ Public-Deklarationen }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function PointIdx(XIdx,YIdx: Integer): TPointIdx;
begin
Result.XIdx := XIdx;
Result.YIdx := YIdx;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
CalcDotPositions;
end;
procedure TForm1.CalcDotPositions;
var
LCntrHorz, LCntrVert: Integer;
LLeftHorz, LTopVert: Integer;
LRghtHorz, LBotVert: Integer;
ix: Integer;
iy: Integer;
begin
LCntrHorz := PB.Width
Div 2;
LLeftHorz := DOT_RADIUS + Round(LCntrHorz*0.1);
LRghtHorz := PB.Width - LLeftHorz;
LCntrVert := PB.Height
Div 2;
LTopVert := LCntrVert - (LRghtHorz - LCntrHorz);
LBotVert := LCntrVert + (LRghtHorz - LCntrHorz);
fDots[0,0].Pos := Point(LLeftHorz, LTopVert);
fDots[0,1].Pos := Point(LLeftHorz, LCntrVert);
fDots[0,2].Pos := Point(LLeftHorz, LBotVert);
fDots[1,0].Pos := Point(LCntrHorz, LTopVert);
fDots[1,1].Pos := Point(LCntrHorz, LCntrVert);
fDots[1,2].Pos := Point(LCntrHorz, LBotVert);
fDots[2,0].Pos := Point(LRghtHorz, LTopVert);
fDots[2,1].Pos := Point(LRghtHorz, LCntrVert);
fDots[2,2].Pos := Point(LRghtHorz, LBotVert);
for ix := 0
to maxXDots-1
do
begin
for iy := 0
to maxYDots-1
do
begin
fDots[ix,iy].Selected := FALSE;
fDots[ix,iy].Bounds := Rect(
fDots[ix,iy].Pos.X - DOT_RADIUS,
fDots[ix,iy].Pos.Y - DOT_RADIUS,
fDots[ix,iy].Pos.X + DOT_RADIUS,
fDots[ix,iy].Pos.Y + DOT_RADIUS
);
end;
end;
end;
procedure TForm1.ResetDotSelection;
var
ix,iy: Integer;
begin
for ix := 0
to maxXDots-1
do
begin
for iy := 0
to maxYDots-1
do
begin
fDots[ix,iy].Selected := FALSE;
end;
end;
end;
function TForm1.MouseNearDots(X,Y: Integer;
Var DXIdx, DYIdx: Integer): Boolean;
var
ix,iy: Integer;
LRect: TRect;
begin
Result := FALSE;
for ix := 0
to maxXDots-1
do
begin
for iy := 0
to maxYDots-1
do
begin
LRect := fDots[ix, iy].Bounds;
InflateRect(LRect, MOUSE_SLACK, MOUSE_SLACK);
if PtInRect(LRect, Point(X,Y))
then
begin
DXIdx := ix;
DYIdx := iy;
Result := TRUE;
Break;
end;
end;
end;
end;
function TForm1.HasLinkTo(ADot: TDot): Boolean;
begin
Result := (ADot.LinkTo.XIdx >= 0)
And (ADot.LinkTo.YIdx >= 0);
end;
procedure TForm1.PBMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
dx, dy: Integer;
begin
ResetDotSelection;
if MouseNearDots(X,Y, dx,dy)
then
begin
fDown := TRUE;
fPO := PointIdx(dx,dy);
fDots[dx, dy].Selected := TRUE;
fDots[dx, dy].LinkTo := PointIdx(-1, -1);
end;
end;
procedure TForm1.PBMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
dx: Integer;
dy: Integer;
begin
if fDown
then
begin
if MouseNearDots(X,Y, dx, dy)
and not fDots[dx, dy].Selected
then
begin
fCurPos := fDots[dx,dy].Pos;
fDots[dx, dy].Selected := TRUE;
fDots[dx, dy].LinkTo := fPO;
fPO := PointIdx(dx, dy);
end
else
fCurPos := Point(X,Y);
Invalidate;
end;
end;
procedure TForm1.PBMouseUp(Sender: TObject; Button: TMouseButton; Shift:
TShiftState; X, Y: Integer);
begin
fDown := FALSE;
PB.Invalidate;
end;
procedure TForm1.PBPaint(Sender: TObject);
var
ix,iy: Integer;
begin
// paint dots
PB.Canvas.Brush.Color := clSilver;
PB.Canvas.Brush.Style := bsSolid;
PB.Canvas.Pen.Color := clBlack;
PB.Canvas.Pen.Style := psSolid;
PB.Canvas.Pen.Width := 1;
for iy := 0
to maxYDots-1
do
begin
for ix := 0
to maxXDots-1
do
begin
PB.Canvas.Ellipse(fDots[ix,iy].Bounds);
end;
end;
// draw fixed segemts
PB.Canvas.Pen.Color := clYellow;
PB.Canvas.Pen.Width := 6;
for iy := 0
to maxYDots-1
do
begin
for ix := 0
to maxXDots-1
do
begin
if fDots[ix,iy].Selected
And HasLinkTo(fDots[ix,iy])
then
begin
PB.Canvas.MoveTo( fDots[ix, iy].Pos.X, fDots[ix, iy].Pos.Y );
PB.Canvas.LineTo( fDots[fDots[ix, iy].LinkTo.XIdx, fDots[ix, iy].LinkTo.YIdx].Pos.X,
fDots[fDots[ix, iy].LinkTo.XIdx, fDots[ix, iy].LinkTo.YIdx].Pos.Y );
end;
end;
end;
// draw current segment
if fDown
then
begin
PB.Canvas.Pen.Color := clYellow;
PB.Canvas.Pen.Width := 6;
PB.Canvas.MoveTo( fDots[fPO.XIdx, fPO.YIdx].Pos.X, fDots[fPO.XIdx, fPO.YIdx].Pos.Y );
PB.Canvas.LineTo( fCurPos.X, fCurPos.Y );
end;
end;
end.