|
@@ -85,6 +85,7 @@ type
|
|
FPoints: array of record
|
|
FPoints: array of record
|
|
coord: TPointF;
|
|
coord: TPointF;
|
|
editorIndex: integer;
|
|
editorIndex: integer;
|
|
|
|
+ data: pointer;
|
|
end;
|
|
end;
|
|
FCenterPoint: TPointF;
|
|
FCenterPoint: TPointF;
|
|
FCenterPointEditorIndex: integer;
|
|
FCenterPointEditorIndex: integer;
|
|
@@ -101,11 +102,17 @@ type
|
|
procedure SetClosed(AValue: boolean); virtual;
|
|
procedure SetClosed(AValue: boolean); virtual;
|
|
function PointsEqual(const APoint1, APoint2: TPointF): boolean;
|
|
function PointsEqual(const APoint1, APoint2: TPointF): boolean;
|
|
procedure OnHoverPoint({%H-}ASender: TObject; APointIndex: integer); virtual;
|
|
procedure OnHoverPoint({%H-}ASender: TObject; APointIndex: integer); virtual;
|
|
|
|
+ procedure OnClickPoint({%H-}ASender: TObject; APointIndex: integer; {%H-}AShift: TShiftState); virtual;
|
|
|
|
+ procedure DoClickPoint(APointIndex: integer; {%H-}AShift: TShiftState); virtual;
|
|
|
|
+ function CanMovePoints: boolean; virtual;
|
|
procedure InsertPointAuto;
|
|
procedure InsertPointAuto;
|
|
public
|
|
public
|
|
constructor Create(AContainer: TVectorOriginal); override;
|
|
constructor Create(AContainer: TVectorOriginal); override;
|
|
- procedure AddPoint(const APoint: TPointF);
|
|
|
|
|
|
+ procedure Clear;
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ function AddPoint(const APoint: TPointF): integer;
|
|
function RemovePoint(AIndex: integer): boolean;
|
|
function RemovePoint(AIndex: integer): boolean;
|
|
|
|
+ procedure RemovePointRange(AFromIndex, AToIndexPlus1: integer);
|
|
procedure InsertPoint(AIndex: integer; APoint: TPointF);
|
|
procedure InsertPoint(AIndex: integer; APoint: TPointF);
|
|
procedure MouseMove({%H-}Shift: TShiftState; X, Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
|
|
procedure MouseMove({%H-}Shift: TShiftState; X, Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
|
|
procedure MouseDown(RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
|
|
procedure MouseDown(RightButton: boolean; {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: single; var {%H-}ACursor: TOriginalEditorCursor; var AHandled: boolean); override;
|
|
@@ -141,15 +148,22 @@ type
|
|
TCurveShape = class(TPolylineShape)
|
|
TCurveShape = class(TPolylineShape)
|
|
private
|
|
private
|
|
FSplineStyle: TSplineStyle;
|
|
FSplineStyle: TSplineStyle;
|
|
|
|
+ function GetCurveMode(AIndex: integer): TEasyBezierCurveMode;
|
|
|
|
+ procedure SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
|
|
procedure SetSplineStyle(AValue: TSplineStyle);
|
|
procedure SetSplineStyle(AValue: TSplineStyle);
|
|
protected
|
|
protected
|
|
function GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF; override;
|
|
function GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF; override;
|
|
|
|
+ function CanMovePoints: boolean; override;
|
|
|
|
+ procedure DoClickPoint(APointIndex: integer; {%H-}AShift: TShiftState); override;
|
|
public
|
|
public
|
|
|
|
+ class function Usermodes: TVectorShapeUsermodes; override;
|
|
constructor Create(AContainer: TVectorOriginal); override;
|
|
constructor Create(AContainer: TVectorOriginal); override;
|
|
|
|
+ procedure KeyPress(UTF8Key: string; var AHandled: boolean); override;
|
|
procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
|
|
procedure LoadFromStorage(AStorage: TBGRACustomOriginalStorage); override;
|
|
procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
|
|
procedure SaveToStorage(AStorage: TBGRACustomOriginalStorage); override;
|
|
class function StorageClassName: RawByteString; override;
|
|
class function StorageClassName: RawByteString; override;
|
|
property SplineStyle: TSplineStyle read FSplineStyle write SetSplineStyle;
|
|
property SplineStyle: TSplineStyle read FSplineStyle write SetSplineStyle;
|
|
|
|
+ property CurveMode[AIndex: integer]: TEasyBezierCurveMode read GetCurveMode write SetCurveMode;
|
|
end;
|
|
end;
|
|
|
|
|
|
implementation
|
|
implementation
|
|
@@ -840,8 +854,9 @@ begin
|
|
if AIndex = length(FPoints) then
|
|
if AIndex = length(FPoints) then
|
|
begin
|
|
begin
|
|
setlength(FPoints, length(FPoints)+1);
|
|
setlength(FPoints, length(FPoints)+1);
|
|
- FPoints[high(FPoints)].coord := AValue;
|
|
|
|
- FPoints[high(FPoints)].editorIndex := -1;
|
|
|
|
|
|
+ FPoints[AIndex].coord := AValue;
|
|
|
|
+ FPoints[AIndex].editorIndex := -1;
|
|
|
|
+ FPoints[AIndex].data := nil;
|
|
end
|
|
end
|
|
else
|
|
else
|
|
FPoints[AIndex].coord := AValue;
|
|
FPoints[AIndex].coord := AValue;
|
|
@@ -878,7 +893,7 @@ var
|
|
i: Integer;
|
|
i: Integer;
|
|
begin
|
|
begin
|
|
FCurPoint:= -1;
|
|
FCurPoint:= -1;
|
|
- for i:= 0 to high(FPoints) do
|
|
|
|
|
|
+ for i:= 0 to PointCount-1 do
|
|
if FPoints[i].editorIndex = APointIndex then
|
|
if FPoints[i].editorIndex = APointIndex then
|
|
begin
|
|
begin
|
|
FCurPoint:= i;
|
|
FCurPoint:= i;
|
|
@@ -907,15 +922,11 @@ var
|
|
add: Boolean;
|
|
add: Boolean;
|
|
begin
|
|
begin
|
|
add := AValue = vsuCreate;
|
|
add := AValue = vsuCreate;
|
|
- if add and (length(FPoints) = 0) then exit;
|
|
|
|
|
|
+ if add and (PointCount = 0) then exit;
|
|
if FAddingPoint and not add then
|
|
if FAddingPoint and not add then
|
|
begin
|
|
begin
|
|
- if (length(FPoints)>1) and PointsEqual(FPoints[high(FPoints)].coord,FPoints[high(FPoints)-1].coord) then
|
|
|
|
- begin
|
|
|
|
- BeginUpdate;
|
|
|
|
- setlength(FPoints, length(FPoints)-1);
|
|
|
|
- EndUpdate;
|
|
|
|
- end;
|
|
|
|
|
|
+ if (PointCount>1) and PointsEqual(Points[PointCount-1],Points[PointCount-2]) then
|
|
|
|
+ RemovePoint(PointCount-1);
|
|
FAddingPoint:= add;
|
|
FAddingPoint:= add;
|
|
end else
|
|
end else
|
|
if not FAddingPoint and add then
|
|
if not FAddingPoint and add then
|
|
@@ -948,7 +959,7 @@ begin
|
|
FHoverPoint:= -1;
|
|
FHoverPoint:= -1;
|
|
if APointIndex <> -1 then
|
|
if APointIndex <> -1 then
|
|
begin
|
|
begin
|
|
- for i:= 0 to high(FPoints) do
|
|
|
|
|
|
+ for i:= 0 to PointCount-1 do
|
|
if FPoints[i].editorIndex = APointIndex then
|
|
if FPoints[i].editorIndex = APointIndex then
|
|
begin
|
|
begin
|
|
FHoverPoint:= i;
|
|
FHoverPoint:= i;
|
|
@@ -957,6 +968,33 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TCustomPolypointShape.OnClickPoint(ASender: TObject;
|
|
|
|
+ APointIndex: integer; AShift: TShiftState);
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+begin
|
|
|
|
+ if APointIndex <> -1 then
|
|
|
|
+ begin
|
|
|
|
+ for i:= 0 to PointCount-1 do
|
|
|
|
+ if FPoints[i].editorIndex = APointIndex then
|
|
|
|
+ begin
|
|
|
|
+ DoClickPoint(i, AShift);
|
|
|
|
+ break;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TCustomPolypointShape.DoClickPoint(APointIndex: integer;
|
|
|
|
+ AShift: TShiftState);
|
|
|
|
+begin
|
|
|
|
+ //nothing
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCustomPolypointShape.CanMovePoints: boolean;
|
|
|
|
+begin
|
|
|
|
+ result := true;
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TCustomPolypointShape.InsertPointAuto;
|
|
procedure TCustomPolypointShape.InsertPointAuto;
|
|
var
|
|
var
|
|
bestSegmentIndex, i: Integer;
|
|
bestSegmentIndex, i: Integer;
|
|
@@ -1008,22 +1046,54 @@ begin
|
|
FHoverPoint:= -1;
|
|
FHoverPoint:= -1;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TCustomPolypointShape.AddPoint(const APoint: TPointF);
|
|
|
|
|
|
+procedure TCustomPolypointShape.Clear;
|
|
begin
|
|
begin
|
|
- Points[PointCount] := APoint;
|
|
|
|
|
|
+ RemovePointRange(0, PointCount);
|
|
end;
|
|
end;
|
|
|
|
|
|
-function TCustomPolypointShape.RemovePoint(AIndex: integer): boolean;
|
|
|
|
|
|
+destructor TCustomPolypointShape.Destroy;
|
|
var
|
|
var
|
|
i: Integer;
|
|
i: Integer;
|
|
|
|
+begin
|
|
|
|
+ for i := 0 to PointCount-1 do
|
|
|
|
+ begin
|
|
|
|
+ FreeMem(FPoints[i].data);
|
|
|
|
+ FPoints[i].data := nil;
|
|
|
|
+ end;
|
|
|
|
+ inherited Destroy;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCustomPolypointShape.AddPoint(const APoint: TPointF): integer;
|
|
|
|
+begin
|
|
|
|
+ result := PointCount;
|
|
|
|
+ Points[result] := APoint;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCustomPolypointShape.RemovePoint(AIndex: integer): boolean;
|
|
begin
|
|
begin
|
|
if (AIndex < 0) or (AIndex >= PointCount) then exit(false);
|
|
if (AIndex < 0) or (AIndex >= PointCount) then exit(false);
|
|
|
|
+ RemovePointRange(AIndex,AIndex+1);
|
|
|
|
+ result := true;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TCustomPolypointShape.RemovePointRange(AFromIndex, AToIndexPlus1: integer);
|
|
|
|
+var
|
|
|
|
+ i, delCount: Integer;
|
|
|
|
+begin
|
|
|
|
+ if AFromIndex < 0 then AFromIndex:= 0;
|
|
|
|
+ if AToIndexPlus1 > PointCount then AToIndexPlus1:= PointCount;
|
|
|
|
+ if AFromIndex >= AToIndexPlus1 then exit;
|
|
BeginUpdate;
|
|
BeginUpdate;
|
|
- for i := AIndex to PointCount-2 do
|
|
|
|
- FPoints[i] := FPoints[i+1];
|
|
|
|
- setlength(FPoints, PointCount-1);
|
|
|
|
|
|
+ for i := AFromIndex to AToIndexPlus1-1 do
|
|
|
|
+ begin
|
|
|
|
+ freemem(FPoints[i].data);
|
|
|
|
+ FPoints[i].data := nil;
|
|
|
|
+ end;
|
|
|
|
+ delCount := AToIndexPlus1-AFromIndex;
|
|
|
|
+ for i := AFromIndex to PointCount-DelCount-1 do
|
|
|
|
+ FPoints[i] := FPoints[i+delCount];
|
|
|
|
+ setlength(FPoints, PointCount-delCount);
|
|
EndUpdate;
|
|
EndUpdate;
|
|
- result := true;
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TCustomPolypointShape.InsertPoint(AIndex: integer; APoint: TPointF);
|
|
procedure TCustomPolypointShape.InsertPoint(AIndex: integer; APoint: TPointF);
|
|
@@ -1037,6 +1107,7 @@ begin
|
|
FPoints[i] := FPoints[i-1];
|
|
FPoints[i] := FPoints[i-1];
|
|
FPoints[AIndex].coord := APoint;
|
|
FPoints[AIndex].coord := APoint;
|
|
FPoints[AIndex].editorIndex:= -1;
|
|
FPoints[AIndex].editorIndex:= -1;
|
|
|
|
+ FPoints[AIndex].data := nil;
|
|
EndUpdate;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
|
|
@@ -1046,9 +1117,7 @@ begin
|
|
FMousePos := PointF(X,Y);
|
|
FMousePos := PointF(X,Y);
|
|
if FAddingPoint then
|
|
if FAddingPoint then
|
|
begin
|
|
begin
|
|
- BeginUpdate;
|
|
|
|
- FPoints[high(FPoints)].coord := FMousePos;
|
|
|
|
- EndUpdate;
|
|
|
|
|
|
+ Points[PointCount-1] := FMousePos;
|
|
AHandled:= true;
|
|
AHandled:= true;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
@@ -1061,8 +1130,8 @@ begin
|
|
begin
|
|
begin
|
|
if not RightButton then
|
|
if not RightButton then
|
|
begin
|
|
begin
|
|
- if (length(FPoints)>1) and not PointsEqual(FPoints[high(FPoints)].coord,FPoints[high(FPoints)-1].coord) then
|
|
|
|
- AddPoint(FPoints[high(FPoints)].coord);
|
|
|
|
|
|
+ if (PointCount>1) and not PointsEqual(Points[PointCount-1],Points[PointCount-2]) then
|
|
|
|
+ AddPoint(Points[PointCount-1]);
|
|
end else
|
|
end else
|
|
Usermode := vsuEdit;
|
|
Usermode := vsuEdit;
|
|
AHandled:= true;
|
|
AHandled:= true;
|
|
@@ -1078,7 +1147,7 @@ begin
|
|
begin
|
|
begin
|
|
BeginUpdate;
|
|
BeginUpdate;
|
|
RemovePoint(FHoverPoint);
|
|
RemovePoint(FHoverPoint);
|
|
- if (FHoverPoint < PointCount) and IsEmptyPointF(FPoints[FHoverPoint].coord) then RemovePoint(FHoverPoint);
|
|
|
|
|
|
+ if (FHoverPoint < PointCount) and IsEmptyPointF(Points[FHoverPoint]) then RemovePoint(FHoverPoint);
|
|
EndUpdate;
|
|
EndUpdate;
|
|
if PointCount = 0 then self.Remove;
|
|
if PointCount = 0 then self.Remove;
|
|
end;
|
|
end;
|
|
@@ -1087,11 +1156,9 @@ begin
|
|
if (Key = skBackspace) and FAddingPoint then
|
|
if (Key = skBackspace) and FAddingPoint then
|
|
begin
|
|
begin
|
|
If PointCount <= 2 then self.Remove else
|
|
If PointCount <= 2 then self.Remove else
|
|
- If isEmptyPointF(FPoints[PointCount-3].coord) then
|
|
|
|
|
|
+ If isEmptyPointF(Points[PointCount-3]) then
|
|
begin
|
|
begin
|
|
- BeginUpdate;
|
|
|
|
- setlength(FPoints, PointCount-3);
|
|
|
|
- EndUpdate;
|
|
|
|
|
|
+ RemovePointRange(PointCount-3, PointCount);
|
|
Usermode:= vsuEdit;
|
|
Usermode:= vsuEdit;
|
|
end else
|
|
end else
|
|
RemovePoint(PointCount-2);
|
|
RemovePoint(PointCount-2);
|
|
@@ -1118,6 +1185,7 @@ var
|
|
begin
|
|
begin
|
|
BeginUpdate;
|
|
BeginUpdate;
|
|
inherited LoadFromStorage(AStorage);
|
|
inherited LoadFromStorage(AStorage);
|
|
|
|
+ Clear;
|
|
x := AStorage.FloatArray['x'];
|
|
x := AStorage.FloatArray['x'];
|
|
y := AStorage.FloatArray['y'];
|
|
y := AStorage.FloatArray['y'];
|
|
setlength(FPoints, max(length(x),length(y)));
|
|
setlength(FPoints, max(length(x),length(y)));
|
|
@@ -1125,6 +1193,7 @@ begin
|
|
begin
|
|
begin
|
|
FPoints[i].coord := PointF(x[i],y[i]);
|
|
FPoints[i].coord := PointF(x[i],y[i]);
|
|
FPoints[i].editorIndex := -1;
|
|
FPoints[i].editorIndex := -1;
|
|
|
|
+ FPoints[i].data := nil;
|
|
end;
|
|
end;
|
|
FClosed:= AStorage.Bool['closed'];
|
|
FClosed:= AStorage.Bool['closed'];
|
|
EndUpdate;
|
|
EndUpdate;
|
|
@@ -1153,6 +1222,7 @@ var
|
|
i, nb: Integer;
|
|
i, nb: Integer;
|
|
begin
|
|
begin
|
|
AEditor.AddStartMoveHandler(@OnStartMove);
|
|
AEditor.AddStartMoveHandler(@OnStartMove);
|
|
|
|
+ AEditor.AddClickPointHandler(@OnClickPoint);
|
|
AEditor.AddHoverPointHandler(@OnHoverPoint);
|
|
AEditor.AddHoverPointHandler(@OnHoverPoint);
|
|
nb := 0;
|
|
nb := 0;
|
|
FCenterPoint := PointF(0,0);
|
|
FCenterPoint := PointF(0,0);
|
|
@@ -1167,7 +1237,10 @@ begin
|
|
end
|
|
end
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
- FPoints[i].editorIndex := AEditor.AddPoint(Points[i], @OnMovePoint, false);
|
|
|
|
|
|
+ if CanMovePoints then
|
|
|
|
+ FPoints[i].editorIndex := AEditor.AddPoint(Points[i], @OnMovePoint, false)
|
|
|
|
+ else
|
|
|
|
+ FPoints[i].editorIndex := AEditor.AddFixedPoint(Points[i], false);
|
|
FCenterPoint += Points[i];
|
|
FCenterPoint += Points[i];
|
|
inc(nb);
|
|
inc(nb);
|
|
end;
|
|
end;
|
|
@@ -1307,13 +1380,66 @@ begin
|
|
EndUpdate;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+function TCurveShape.GetCurveMode(AIndex: integer): TEasyBezierCurveMode;
|
|
|
|
+begin
|
|
|
|
+ if (AIndex < 0) or (AIndex >= PointCount) then exit(cmCurve);
|
|
|
|
+ if Assigned(FPoints[AIndex].data) then
|
|
|
|
+ result := TEasyBezierCurveMode(FPoints[AIndex].data^)
|
|
|
|
+ else
|
|
|
|
+ result := cmAuto;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TCurveShape.SetCurveMode(AIndex: integer; AValue: TEasyBezierCurveMode);
|
|
|
|
+begin
|
|
|
|
+ if (AIndex < 0) or (AIndex >= PointCount) then exit;
|
|
|
|
+ if CurveMode[AIndex] = AValue then exit;
|
|
|
|
+ BeginUpdate;
|
|
|
|
+ if FPoints[AIndex].data = nil then FPoints[AIndex].data := getmem(sizeof(TEasyBezierCurveMode));
|
|
|
|
+ TEasyBezierCurveMode(FPoints[AIndex].data^) := AValue;
|
|
|
|
+ EndUpdate
|
|
|
|
+end;
|
|
|
|
+
|
|
function TCurveShape.GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF;
|
|
function TCurveShape.GetCurve(AMatrix: TAffineMatrix): ArrayOfTPointF;
|
|
var
|
|
var
|
|
pts: array of TPointF;
|
|
pts: array of TPointF;
|
|
|
|
+ cm: array of TEasyBezierCurveMode;
|
|
|
|
+ i: Integer;
|
|
|
|
+ eb: TEasyBezierCurve;
|
|
begin
|
|
begin
|
|
pts := inherited GetCurve(AMatrix);
|
|
pts := inherited GetCurve(AMatrix);
|
|
- if Closed then result := ComputeClosedSpline(pts, FSplineStyle)
|
|
|
|
- else result := ComputeOpenedSpline(pts, FSplineStyle);
|
|
|
|
|
|
+ if FSplineStyle = ssEasyBezier then
|
|
|
|
+ begin
|
|
|
|
+ setlength(cm, PointCount);
|
|
|
|
+ for i := 0 to PointCount-1 do
|
|
|
|
+ cm[i] := CurveMode[i];
|
|
|
|
+ eb := EasyBezierCurve(pts, Closed, cm);
|
|
|
|
+ result := eb.ToPoints;
|
|
|
|
+ end else
|
|
|
|
+ begin
|
|
|
|
+ if Closed then result := ComputeClosedSpline(pts, FSplineStyle)
|
|
|
|
+ else result := ComputeOpenedSpline(pts, FSplineStyle);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+function TCurveShape.CanMovePoints: boolean;
|
|
|
|
+begin
|
|
|
|
+ Result:= Usermode in [vsuCreate,vsuEdit];
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TCurveShape.DoClickPoint(APointIndex: integer; AShift: TShiftState);
|
|
|
|
+begin
|
|
|
|
+ case Usermode of
|
|
|
|
+ vsuCurveSetAuto: CurveMode[APointIndex] := cmAuto;
|
|
|
|
+ vsuCurveSetCurve: CurveMode[APointIndex] := cmCurve;
|
|
|
|
+ vsuCurveSetAngle: CurveMode[APointIndex] := cmAngle;
|
|
|
|
+ else
|
|
|
|
+ inherited DoClickPoint(APointIndex, AShift);
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+class function TCurveShape.Usermodes: TVectorShapeUsermodes;
|
|
|
|
+begin
|
|
|
|
+ Result:=inherited Usermodes + [vsuCurveSetAuto, vsuCurveSetCurve, vsuCurveSetAngle];
|
|
end;
|
|
end;
|
|
|
|
|
|
constructor TCurveShape.Create(AContainer: TVectorOriginal);
|
|
constructor TCurveShape.Create(AContainer: TVectorOriginal);
|
|
@@ -1322,7 +1448,34 @@ begin
|
|
FSplineStyle:= ssEasyBezier;
|
|
FSplineStyle:= ssEasyBezier;
|
|
end;
|
|
end;
|
|
|
|
|
|
|
|
+procedure TCurveShape.KeyPress(UTF8Key: string; var AHandled: boolean);
|
|
|
|
+begin
|
|
|
|
+ if (FHoverPoint >= 0) and (FHoverPoint < PointCount) then
|
|
|
|
+ begin
|
|
|
|
+ if (UTF8Key = 'A') or (UTF8Key = 'a') then
|
|
|
|
+ begin
|
|
|
|
+ CurveMode[FHoverPoint] := cmAuto;
|
|
|
|
+ AHandled := true;
|
|
|
|
+ end else
|
|
|
|
+ if (UTF8Key = 'S') or (UTF8Key = 's') then
|
|
|
|
+ begin
|
|
|
|
+ CurveMode[FHoverPoint] := cmCurve;
|
|
|
|
+ AHandled:= true;
|
|
|
|
+ end else
|
|
|
|
+ if (UTF8Key = 'X') or (UTF8Key = 'x') then
|
|
|
|
+ begin
|
|
|
|
+ CurveMode[FHoverPoint] := cmAngle;
|
|
|
|
+ AHandled:= true;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+ if not AHandled then
|
|
|
|
+ inherited KeyPress(UTF8Key, AHandled);
|
|
|
|
+end;
|
|
|
|
+
|
|
procedure TCurveShape.LoadFromStorage(AStorage: TBGRACustomOriginalStorage);
|
|
procedure TCurveShape.LoadFromStorage(AStorage: TBGRACustomOriginalStorage);
|
|
|
|
+var
|
|
|
|
+ i: Integer;
|
|
|
|
+ cm: array of Single;
|
|
begin
|
|
begin
|
|
BeginUpdate;
|
|
BeginUpdate;
|
|
inherited LoadFromStorage(AStorage);
|
|
inherited LoadFromStorage(AStorage);
|
|
@@ -1337,11 +1490,25 @@ begin
|
|
else
|
|
else
|
|
{'easy-bezier'} SplineStyle := ssEasyBezier;
|
|
{'easy-bezier'} SplineStyle := ssEasyBezier;
|
|
end;
|
|
end;
|
|
|
|
+ if SplineStyle = ssEasyBezier then
|
|
|
|
+ begin
|
|
|
|
+ cm := AStorage.FloatArray['curve-mode'];
|
|
|
|
+ for i := 0 to min(high(cm),PointCount-1) do
|
|
|
|
+ case round(cm[i]) of
|
|
|
|
+ 1: CurveMode[i] := cmCurve;
|
|
|
|
+ 2: CurveMode[i] := cmAngle;
|
|
|
|
+ end;
|
|
|
|
+ if length(cm) < PointCount then
|
|
|
|
+ for i:= length(cm) to PointCount-1 do
|
|
|
|
+ CurveMode[i] := cmCurve;
|
|
|
|
+ end;
|
|
EndUpdate;
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TCurveShape.SaveToStorage(AStorage: TBGRACustomOriginalStorage);
|
|
procedure TCurveShape.SaveToStorage(AStorage: TBGRACustomOriginalStorage);
|
|
var s: string;
|
|
var s: string;
|
|
|
|
+ cm: array of single;
|
|
|
|
+ i: Integer;
|
|
begin
|
|
begin
|
|
inherited SaveToStorage(AStorage);
|
|
inherited SaveToStorage(AStorage);
|
|
case SplineStyle of
|
|
case SplineStyle of
|
|
@@ -1356,6 +1523,13 @@ begin
|
|
else s := '';
|
|
else s := '';
|
|
end;
|
|
end;
|
|
AStorage.RawString['spline-style'] := s;
|
|
AStorage.RawString['spline-style'] := s;
|
|
|
|
+ if SplineStyle = ssEasyBezier then
|
|
|
|
+ begin
|
|
|
|
+ setlength(cm, PointCount);
|
|
|
|
+ for i := 0 to PointCount-1 do
|
|
|
|
+ cm[i] := ord(CurveMode[i]);
|
|
|
|
+ AStorage.FloatArray['curve-mode'] := cm;
|
|
|
|
+ end;
|
|
end;
|
|
end;
|
|
|
|
|
|
class function TCurveShape.StorageClassName: RawByteString;
|
|
class function TCurveShape.StorageClassName: RawByteString;
|