Browse Source

fill style for pen

Unknown 6 năm trước cách đây
mục cha
commit
7890087fbb

+ 4 - 3
lazpaintcontrols/lcvectorialfillcontrol.pas

@@ -56,7 +56,7 @@ type
     destructor Destroy; override;
     procedure AssignFill(AFill: TVectorialFill);
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
-    procedure UpdateShapeFill(AShape: TVectorShape);
+    procedure UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
     property FillType: TVectorialFillType read GetFillType write SetFillType;
     property SolidColor: TBGRAPixel read GetSolidColor write SetSolidColor;
     property GradientType: TGradientType read GetGradType write SetGradientType;
@@ -282,9 +282,10 @@ begin
   result := FInterface.CreateShapeFill(AShape);
 end;
 
-procedure TLCVectorialFillControl.UpdateShapeFill(AShape: TVectorShape);
+procedure TLCVectorialFillControl.UpdateShapeFill(AShape: TVectorShape;
+  ABackFill: boolean);
 begin
-  FInterface.UpdateShapeFill(AShape);
+  FInterface.UpdateShapeFill(AShape, ABackFill);
 end;
 
 end.

+ 16 - 7
lazpaintcontrols/lcvectorialfillinterface.pas

@@ -129,7 +129,7 @@ type
     function GetTextureThumbnail(AWidth, AHeight: integer; ABackColor: TColor): TBitmap;
     procedure AssignFill(AFill: TVectorialFill);
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
-    procedure UpdateShapeFill(AShape: TVectorShape);
+    procedure UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
     property FillType: TVectorialFillType read FFillType write SetFillType;
     property SolidColor: TBGRAPixel read FSolidColor write SetSolidColor;
     property GradientType: TGradientType read FGradType write SetGradientType;
@@ -922,20 +922,26 @@ begin
   else result := nil; //none
 end;
 
-procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape);
+procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
 var
   vectorFill: TVectorialFill;
+  curFill: TVectorialFill;
 begin
+  if ABackFill then
+    curFill:= AShape.BackFill
+  else
+    curFill:= AShape.PenFill;
+
   if (FillType = vftTexture) and (TextureOpacity = 0) then
     vectorFill := nil else
-  if (FillType = vftTexture) and (AShape.BackFill.FillType = vftTexture) then
+  if (FillType = vftTexture) and (curFill.FillType = vftTexture) then
   begin
-    vectorFill := TVectorialFill.CreateAsTexture(Texture, AShape.BackFill.TextureMatrix,
+    vectorFill := TVectorialFill.CreateAsTexture(Texture, curFill.TextureMatrix,
                                                  TextureOpacity, TextureRepetition);
   end
-  else if (FillType = vftGradient) and (AShape.BackFill.FillType = vftGradient) then
+  else if (FillType = vftGradient) and (curFill.FillType = vftGradient) then
   begin
-    vectorFill := AShape.BackFill.Duplicate;
+    vectorFill := curFill.Duplicate;
     vectorFill.Gradient.StartColor := GradStartColor;
     vectorFill.Gradient.EndColor := GradEndColor;
     vectorFill.Gradient.GradientType := GradientType;
@@ -944,7 +950,10 @@ begin
   end else
     vectorFill := CreateShapeFill(AShape);
 
-  AShape.BackFill:= vectorFill;
+  if ABackFill then
+    AShape.BackFill:= vectorFill
+  else
+    AShape.PenFill:= vectorFill;
   vectorFill.Free;
 end;
 

+ 60 - 16
lazpaintcontrols/lcvectororiginal.pas

@@ -20,9 +20,9 @@ type
 
   TRenderBoundsOption = (rboAssumePenFill, rboAssumeBackFill);
   TRenderBoundsOptions = set of TRenderBoundsOption;
-  TVectorShapeField = (vsfPenColor, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill);
+  TVectorShapeField = (vsfPenFill, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill);
   TVectorShapeFields = set of TVectorShapeField;
-  TVectorShapeUsermode = (vsuEdit, vsuCreate, vsuEditBackFill,
+  TVectorShapeUsermode = (vsuEdit, vsuCreate, vsuEditPenFill, vsuEditBackFill,
                           vsuCurveSetAuto, vsuCurveSetCurve, vsuCurveSetAngle);
   TVectorShapeUsermodes = set of TVectorShapeUsermode;
 
@@ -34,8 +34,7 @@ type
     FOnEditingChange: TShapeEditingChangeEvent;
     FUpdateCount: integer;
     FBoundsBeforeUpdate: TRectF;
-    FPenColor: TBGRAPixel;
-    FBackFill: TVectorialFill;
+    FPenFill, FBackFill: TVectorialFill;
     FPenWidth: single;
     FStroker: TBGRAPenStroker;
     FUsermode: TVectorShapeUsermode;
@@ -52,11 +51,13 @@ type
     function GetPenStyle: TBGRAPenStyle; virtual;
     function GetJoinStyle: TPenJoinStyle;
     function GetBackFill: TVectorialFill; virtual;
+    function GetPenFill: TVectorialFill; virtual;
     procedure SetPenColor(AValue: TBGRAPixel); virtual;
     procedure SetPenWidth(AValue: single); virtual;
     procedure SetPenStyle({%H-}AValue: TBGRAPenStyle); virtual;
     procedure SetJoinStyle(AValue: TPenJoinStyle);
     procedure SetBackFill(AValue: TVectorialFill); virtual;
+    procedure SetPenFill(AValue: TVectorialFill); virtual;
     procedure SetUsermode(AValue: TVectorShapeUsermode); virtual;
     procedure LoadFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; var AValue: TVectorialFill);
     procedure SaveFill(AStorage: TBGRACustomOriginalStorage; AObjectName: string; AValue: TVectorialFill);
@@ -93,6 +94,7 @@ type
     property OnChange: TShapeChangeEvent read FOnChange write FOnChange;
     property OnEditingChange: TShapeEditingChangeEvent read FOnEditingChange write FOnEditingChange;
     property PenColor: TBGRAPixel read GetPenColor write SetPenColor;
+    property PenFill: TVectorialFill read GetPenFill write SetPenFill;
     property BackFill: TVectorialFill read GetBackFill write SetBackFill;
     property PenWidth: single read GetPenWidth write SetPenWidth;
     property PenStyle: TBGRAPenStyle read GetPenStyle write SetPenStyle;
@@ -606,6 +608,7 @@ class function TVectorShape.Usermodes: TVectorShapeUsermodes;
 begin
   result := [vsuEdit];
   if vsfBackFill in Fields then result += [vsuEditBackFill];
+  if vsfPenFill in Fields then result += [vsuEditPenFill];
 end;
 
 procedure TVectorShape.SetContainer(AValue: TVectorOriginal);
@@ -652,7 +655,10 @@ end;
 
 function TVectorShape.GetPenColor: TBGRAPixel;
 begin
-  result := FPenColor;
+  if Assigned(FPenFill) then
+    result := FPenFill.SolidColor
+  else
+    result := BGRAPixelTransparent;
 end;
 
 function TVectorShape.GetPenWidth: single;
@@ -675,6 +681,16 @@ begin
   result := FBackFill;
 end;
 
+function TVectorShape.GetPenFill: TVectorialFill;
+begin
+  if FPenFill = nil then
+  begin
+    FPenFill := TVectorialFill.Create;
+    FPenFill.OnChange := @FillChange;
+  end;
+  result := FPenFill;
+end;
+
 function TVectorShape.ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean; AStrokeMatrix: TAffineMatrix): ArrayOfTPointF;
 begin
   Stroker.StrokeMatrix := AStrokeMatrix;
@@ -701,12 +717,12 @@ begin
 end;
 
 procedure TVectorShape.SetPenColor(AValue: TBGRAPixel);
+var
+  vf: TVectorialFill;
 begin
-  if AValue.alpha = 0 then AValue := BGRAPixelTransparent;
-  if FPenColor = AValue then exit;
-  BeginUpdate;
-  FPenColor := AValue;
-  EndUpdate;
+  vf := TVectorialFill.CreateAsSolid(AValue);
+  PenFill := vf;
+  vf.Free;
 end;
 
 procedure TVectorShape.SetPenWidth(AValue: single);
@@ -748,10 +764,33 @@ begin
   EndUpdate;
 end;
 
+procedure TVectorShape.SetPenFill(AValue: TVectorialFill);
+var
+  sharedTex: TBGRABitmap;
+  freeTex: Boolean;
+begin
+  if FPenFill.Equals(AValue) then exit;
+  BeginUpdate;
+  freeTex := Assigned(FPenFill) and Assigned(FPenFill.Texture) and
+    not (Assigned(AValue) and (AValue.FillType = vftTexture) and (AValue.Texture = FPenFill.Texture));
+  if AValue = nil then FreeAndNil(FPenFill) else
+  if AValue.FillType = vftTexture then
+  begin
+    if Assigned(Container) then
+      sharedTex := Container.GetTexture(Container.AddTexture(AValue.Texture))
+    else
+      sharedTex := AValue.Texture;
+    PenFill.SetTexture(sharedTex, AValue.TextureMatrix, AValue.TextureOpacity, AValue.TextureRepetition);
+  end else
+    PenFill.Assign(AValue);
+  if Assigned(Container) and freeTex then Container.DiscardUnusedTextures;
+  EndUpdate;
+end;
+
 constructor TVectorShape.Create(AContainer: TVectorOriginal);
 begin
   FContainer := AContainer;
-  FPenColor := BGRAPixelTransparent;
+  FPenFill := nil;
   FPenWidth := 1;
   FStroker := nil;
   FOnChange := nil;
@@ -764,6 +803,7 @@ end;
 destructor TVectorShape.Destroy;
 begin
   FreeAndNil(FStroker);
+  FreeAndNil(FPenFill);
   FreeAndNil(FBackFill);
   inherited Destroy;
 end;
@@ -776,7 +816,7 @@ begin
   if f <> [] then
   begin
     BeginUpdate;
-    if vsfPenColor in f then PenColor := AStorage.Color['pen-color'];
+    if vsfPenFill in f then LoadFill(AStorage, 'pen', FPenFill);
     if vsfPenWidth in f then PenWidth := AStorage.FloatDef['pen-width', 0];
     if vsfPenStyle in f then PenStyle := AStorage.FloatArray['pen-style'];
     if vsfJoinStyle in f then
@@ -795,7 +835,7 @@ var
   f: TVectorShapeFields;
 begin
   f := Fields;
-  if vsfPenColor in f then AStorage.Color['pen-color'] := PenColor;
+  if vsfPenFill in f then SaveFill(AStorage, 'pen', FPenFill);
   if vsfPenWidth in f then AStorage.Float['pen-width'] := PenWidth;
   if vsfPenStyle in f then AStorage.FloatArray['pen-style'] := PenStyle;
   if vsfJoinStyle in f then
@@ -1172,7 +1212,9 @@ begin
     end else
       prevMode := vsuEdit;
     if Assigned(AShape) and (prevMode = vsuEditBackFill) and (prevMode in AShape.Usermodes) and
-       (AShape.BackFill.FillType in[vftGradient,vftTexture]) then AShape.Usermode:= prevMode;
+       AShape.BackFill.IsEditable then AShape.Usermode:= prevMode;
+    if Assigned(AShape) and (prevMode = vsuEditPenFill) and (prevMode in AShape.Usermodes) and
+       AShape.PenFill.IsEditable then AShape.Usermode:= prevMode;
     FSelectedShape := AShape;
     DiscardFrozenShapes;
     NotifyEditorChange;
@@ -1260,9 +1302,11 @@ begin
     end
     else
     begin
-      if (FSelectedShape.Usermode = vsuEditBackFill) and
-         (FSelectedShape.BackFill.FillType in [vftGradient,vftTexture]) then
+      if (FSelectedShape.Usermode = vsuEditBackFill) and FSelectedShape.BackFill.IsEditable then
         FSelectedShape.BackFill.ConfigureEditor(AEditor)
+      else
+      if (FSelectedShape.Usermode = vsuEditPenFill) and FSelectedShape.PenFill.IsEditable then
+        FSelectedShape.PenFill.ConfigureEditor(AEditor)
       else
         FSelectedShape.ConfigureEditor(AEditor);
     end;

+ 18 - 5
lazpaintcontrols/lcvectorpolyshapes.pas

@@ -199,6 +199,8 @@ begin
     Points[i] := Points[i]+delta;
   if vsfBackFill in Fields then
     BackFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
+  if vsfPenFill in Fields then
+    PenFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
   EndUpdate;
 end;
 
@@ -571,7 +573,7 @@ end;
 
 function TPolylineShape.PenVisible(AAssumePenFill: boolean): boolean;
 begin
-  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and ((PenColor.alpha>0) or AAssumePenFill);
+  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and (not PenFill.IsFullyTransparent or AAssumePenFill);
 end;
 
 function TPolylineShape.BackVisible: boolean;
@@ -581,14 +583,14 @@ end;
 
 class function TPolylineShape.Fields: TVectorShapeFields;
 begin
-  Result:= [vsfPenColor, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill];
+  Result:= [vsfPenFill, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill];
 end;
 
 procedure TPolylineShape.Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix;
   ADraft: boolean);
 var
   pts: array of TPointF;
-  backScan: TBGRACustomScanner;
+  backScan, penScan: TBGRACustomScanner;
 begin
   if not BackVisible and not PenVisible then exit;
   pts := GetCurve(AMatrix);
@@ -614,11 +616,22 @@ begin
   end;
   if PenVisible then
   begin
+    if PenFill.FillType = vftSolid then penScan := nil
+    else penScan := PenFill.CreateScanner(AMatrix, ADraft);
+
     pts := ComputeStroke(pts, Closed, AMatrix);
     if ADraft and (PenWidth > 4) then
-      ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+    begin
+      if Assigned(penScan) then
+        ADest.FillPoly(pts, penScan, dmDrawWithTransparency) else
+        ADest.FillPoly(pts, PenColor, dmDrawWithTransparency);
+    end
     else
-      ADest.FillPolyAntialias(pts, PenColor);
+    begin
+      if Assigned(penScan) then
+        ADest.FillPolyAntialias(pts, penScan) else
+        ADest.FillPolyAntialias(pts, PenColor);
+    end;
   end;
 end;
 

+ 61 - 16
lazpaintcontrols/lcvectorshapes.pas

@@ -247,6 +247,8 @@ begin
   FYAxis += delta;
   if vsfBackFill in Fields then
     BackFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
+  if vsfPenFill in Fields then
+    PenFill.Transform(AffineMatrixTranslation(delta.x, delta.y));
   EndUpdate;
 end;
 
@@ -411,7 +413,7 @@ end;
 
 function TRectShape.PenVisible(AAssumePenFill: boolean): boolean;
 begin
-  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and ((PenColor.alpha>0) or AAssumePenFill);
+  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and (not PenFill.IsFullyTransparent or AAssumePenFill);
 end;
 
 function TRectShape.BackVisible: boolean;
@@ -450,7 +452,7 @@ end;
 
 class function TRectShape.Fields: TVectorShapeFields;
 begin
-  Result:= [vsfPenColor, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill];
+  Result:= [vsfPenFill, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill];
 end;
 
 procedure TRectShape.Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix;
@@ -459,7 +461,7 @@ var
   pts: Array of TPointF;
   orthoRect: TRectF;
   r: TRect;
-  backScan: TBGRACustomScanner;
+  backScan, penScan: TBGRACustomScanner;
 begin
   pts := GetAffineBox(AMatrix, true).AsPolygon;
   If BackVisible then
@@ -502,11 +504,24 @@ begin
   end;
   if PenVisible then
   begin
+    if (PenFill.FillType = vftSolid) then penScan := nil
+    else penScan := PenFill.CreateScanner(AMatrix, ADraft);
+
     pts := ComputeStroke(pts,true, AMatrix);
     if ADraft and (PenWidth > 4) then
-      ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+    begin
+      if Assigned(penScan) then
+        ADest.FillPoly(pts, penScan, dmDrawWithTransparency) else
+        ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+    end
     else
-      ADest.FillPolyAntialias(pts, PenColor);
+    begin
+      if Assigned(penScan) then
+        ADest.FillPolyAntialias(pts, penScan) else
+        ADest.FillPolyAntialias(pts, PenColor);
+    end;
+
+    penScan.Free;
   end;
 end;
 
@@ -571,7 +586,7 @@ end;
 
 function TEllipseShape.PenVisible(AAssumePenFill: boolean): boolean;
 begin
-  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and ((PenColor.alpha>0) or AAssumePenFill);
+  result := (PenWidth>0) and not IsClearPenStyle(PenStyle) and (not PenFill.IsFullyTransparent or AAssumePenFill);
 end;
 
 function TEllipseShape.BackVisible: boolean;
@@ -592,7 +607,7 @@ end;
 
 class function TEllipseShape.Fields: TVectorShapeFields;
 begin
-  Result:= [vsfPenColor, vsfPenWidth, vsfPenStyle, vsfBackFill];
+  Result:= [vsfPenFill, vsfPenWidth, vsfPenStyle, vsfBackFill];
 end;
 
 procedure TEllipseShape.Render(ADest: TBGRABitmap; AMatrix: TAffineMatrix;
@@ -603,7 +618,7 @@ var
   center, radius: TPointF;
   draftPen, isOrtho: Boolean;
   r: TRect;
-  backScan: TBGRACustomScanner;
+  backScan, penScan: TBGRACustomScanner;
   penZoom: Single;
   m: TAffineMatrix;
 begin
@@ -635,26 +650,43 @@ begin
     end;
     if PenVisible then
     begin
-      if IsAffineMatrixScaledRotation(AMatrix) then
+      if PenFill.FillType = vftSolid then penScan := nil
+      else penScan := PenFill.CreateScanner(AMatrix, ADraft);
+      draftPen := ADraft and (PenWidth > 4);
+
+      if IsAffineMatrixScaledRotation(AMatrix) and not (draftPen and Assigned(penScan)) then
       begin
         penZoom := VectLen(AMatrix[1,1],AMatrix[2,1]);
         ADest.CustomPenStyle := PenStyle;
-        draftPen := ADraft and (PenWidth > 4);
         if draftPen then
           ADest.Ellipse(center.x, center.y, radius.x, radius.y, PenColor, PenWidth*penZoom, dmDrawWithTransparency)
         else
-          ADest.EllipseAntialias(center.x, center.y, radius.x, radius.y, PenColor, PenWidth*penZoom);
+        begin
+          if Assigned(penScan) then
+            ADest.EllipseAntialias(center.x, center.y, radius.x, radius.y, penScan, PenWidth*penZoom) else
+            ADest.EllipseAntialias(center.x, center.y, radius.x, radius.y, PenColor, PenWidth*penZoom);
+        end;
         ADest.PenStyle := psSolid;
       end else
       begin
         m:= MatrixForPixelCentered(AMatrix);
         pts := ComputeEllipse(m*FOrigin, m*FXAxis, m*FYAxis);
         pts := ComputeStroke(pts,true, AMatrix);
-        if ADraft and (PenWidth > 4) then
-          ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+        if draftPen then
+        begin
+          if Assigned(penScan) then
+            ADest.FillPoly(pts, penScan, dmDrawWithTransparency) else
+            ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+        end
         else
-          ADest.FillPolyAntialias(pts, PenColor);
+        begin
+          if Assigned(penScan) then
+            ADest.FillPolyAntialias(pts, penScan) else
+            ADest.FillPolyAntialias(pts, PenColor);
+        end;
       end;
+
+      penScan.Free;
     end;
   end else
   begin
@@ -682,11 +714,24 @@ begin
     end;
     if PenVisible then
     begin
+      if PenFill.FillType = vftSolid then penScan := nil
+      else penScan := PenFill.CreateScanner(AMatrix, ADraft);
+
       pts := ComputeStroke(pts,true, AMatrix);
       if ADraft and (PenWidth > 4) then
-        ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+      begin
+        if Assigned(penScan) then
+          ADest.FillPoly(pts, penScan, dmDrawWithTransparency) else
+          ADest.FillPoly(pts, PenColor, dmDrawWithTransparency)
+      end
       else
-        ADest.FillPolyAntialias(pts, PenColor);
+      begin
+        if Assigned(penScan) then
+          ADest.FillPolyAntialias(pts, penScan) else
+          ADest.FillPolyAntialias(pts, PenColor);
+      end;
+
+      penScan.Free;
     end;
   end;
 end;

+ 134 - 142
vectoredit/umain.lfm

@@ -1,5 +1,5 @@
 object Form1: TForm1
-  Left = 608
+  Left = 606
   Height = 622
   Top = 0
   Width = 981
@@ -363,10 +363,10 @@ object Form1: TForm1
         end
       end
       object PanelBasicStyle: TBCPanel
-        Left = 65
+        Left = 216
         Height = 60
         Top = 0
-        Width = 220
+        Width = 185
         Background.Color = clBtnFace
         Background.ColorOpacity = 255
         Background.Gradient1.StartColor = clWhite
@@ -423,138 +423,8 @@ object Form1: TForm1
         Rounding.RoundY = 1
         Rounding.RoundOptions = []
         TabOrder = 1
-        object Label1: TLabel
-          Left = 8
-          Height = 17
-          Top = 20
-          Width = 21
-          Caption = 'Pen'
-          ParentColor = False
-        end
-        object ShapePenColor: TShape
-          Left = 140
-          Height = 25
-          Top = 29
-          Width = 27
-          OnMouseUp = ShapePenColorMouseUp
-        end
-        object UpDownPenAlpha: TBCTrackbarUpdown
-          Left = 166
-          Height = 25
-          Top = 29
-          Width = 48
-          BarExponent = 1
-          Increment = 1
-          LongTimeInterval = 400
-          MinValue = 0
-          MaxValue = 255
-          OnChange = UpDownPenAlphaChange
-          Value = 255
-          ShortTimeInterval = 100
-          Background.Color = clWindow
-          Background.ColorOpacity = 255
-          Background.Gradient1.StartColor = clWhite
-          Background.Gradient1.StartColorOpacity = 255
-          Background.Gradient1.DrawMode = dmSet
-          Background.Gradient1.EndColor = clBlack
-          Background.Gradient1.EndColorOpacity = 255
-          Background.Gradient1.ColorCorrection = True
-          Background.Gradient1.GradientType = gtLinear
-          Background.Gradient1.Point1XPercent = 0
-          Background.Gradient1.Point1YPercent = 0
-          Background.Gradient1.Point2XPercent = 0
-          Background.Gradient1.Point2YPercent = 100
-          Background.Gradient1.Sinus = False
-          Background.Gradient2.StartColor = clWhite
-          Background.Gradient2.StartColorOpacity = 255
-          Background.Gradient2.DrawMode = dmSet
-          Background.Gradient2.EndColor = clBlack
-          Background.Gradient2.EndColorOpacity = 255
-          Background.Gradient2.ColorCorrection = True
-          Background.Gradient2.GradientType = gtLinear
-          Background.Gradient2.Point1XPercent = 0
-          Background.Gradient2.Point1YPercent = 0
-          Background.Gradient2.Point2XPercent = 0
-          Background.Gradient2.Point2YPercent = 100
-          Background.Gradient2.Sinus = False
-          Background.Gradient1EndPercent = 35
-          Background.Style = bbsColor
-          ButtonBackground.Color = clBlack
-          ButtonBackground.ColorOpacity = 255
-          ButtonBackground.Gradient1.StartColor = clBtnShadow
-          ButtonBackground.Gradient1.StartColorOpacity = 255
-          ButtonBackground.Gradient1.DrawMode = dmSet
-          ButtonBackground.Gradient1.EndColor = clBtnFace
-          ButtonBackground.Gradient1.EndColorOpacity = 255
-          ButtonBackground.Gradient1.ColorCorrection = True
-          ButtonBackground.Gradient1.GradientType = gtLinear
-          ButtonBackground.Gradient1.Point1XPercent = 0
-          ButtonBackground.Gradient1.Point1YPercent = -50
-          ButtonBackground.Gradient1.Point2XPercent = 0
-          ButtonBackground.Gradient1.Point2YPercent = 50
-          ButtonBackground.Gradient1.Sinus = False
-          ButtonBackground.Gradient2.StartColor = clBtnFace
-          ButtonBackground.Gradient2.StartColorOpacity = 255
-          ButtonBackground.Gradient2.DrawMode = dmSet
-          ButtonBackground.Gradient2.EndColor = clBtnShadow
-          ButtonBackground.Gradient2.EndColorOpacity = 255
-          ButtonBackground.Gradient2.ColorCorrection = True
-          ButtonBackground.Gradient2.GradientType = gtLinear
-          ButtonBackground.Gradient2.Point1XPercent = 0
-          ButtonBackground.Gradient2.Point1YPercent = 50
-          ButtonBackground.Gradient2.Point2XPercent = 0
-          ButtonBackground.Gradient2.Point2YPercent = 150
-          ButtonBackground.Gradient2.Sinus = False
-          ButtonBackground.Gradient1EndPercent = 50
-          ButtonBackground.Style = bbsGradient
-          ButtonDownBackground.Color = clBtnShadow
-          ButtonDownBackground.ColorOpacity = 255
-          ButtonDownBackground.Gradient1.StartColor = clWhite
-          ButtonDownBackground.Gradient1.StartColorOpacity = 255
-          ButtonDownBackground.Gradient1.DrawMode = dmSet
-          ButtonDownBackground.Gradient1.EndColor = clBlack
-          ButtonDownBackground.Gradient1.EndColorOpacity = 255
-          ButtonDownBackground.Gradient1.ColorCorrection = True
-          ButtonDownBackground.Gradient1.GradientType = gtLinear
-          ButtonDownBackground.Gradient1.Point1XPercent = 0
-          ButtonDownBackground.Gradient1.Point1YPercent = 0
-          ButtonDownBackground.Gradient1.Point2XPercent = 0
-          ButtonDownBackground.Gradient1.Point2YPercent = 100
-          ButtonDownBackground.Gradient1.Sinus = False
-          ButtonDownBackground.Gradient2.StartColor = clWhite
-          ButtonDownBackground.Gradient2.StartColorOpacity = 255
-          ButtonDownBackground.Gradient2.DrawMode = dmSet
-          ButtonDownBackground.Gradient2.EndColor = clBlack
-          ButtonDownBackground.Gradient2.EndColorOpacity = 255
-          ButtonDownBackground.Gradient2.ColorCorrection = True
-          ButtonDownBackground.Gradient2.GradientType = gtLinear
-          ButtonDownBackground.Gradient2.Point1XPercent = 0
-          ButtonDownBackground.Gradient2.Point1YPercent = 0
-          ButtonDownBackground.Gradient2.Point2XPercent = 0
-          ButtonDownBackground.Gradient2.Point2YPercent = 100
-          ButtonDownBackground.Gradient2.Sinus = False
-          ButtonDownBackground.Gradient1EndPercent = 35
-          ButtonDownBackground.Style = bbsColor
-          Border.Color = clWindowText
-          Border.ColorOpacity = 255
-          Border.LightColor = clWhite
-          Border.LightOpacity = 255
-          Border.LightWidth = 0
-          Border.Style = bboSolid
-          Border.Width = 1
-          Rounding.RoundX = 1
-          Rounding.RoundY = 1
-          Rounding.RoundOptions = []
-          Font.Color = clWindowText
-          Font.Name = 'Arial'
-          HasTrackBar = True
-          ArrowColor = clBtnText
-          TabOrder = 0
-          TabStop = True
-          UseDockManager = False
-        end
         object Label3: TLabel
-          Left = 38
+          Left = 5
           Height = 17
           Top = 33
           Width = 32
@@ -562,7 +432,7 @@ object Form1: TForm1
           ParentColor = False
         end
         object UpDownPenWidth: TBCTrackbarUpdown
-          Left = 78
+          Left = 45
           Height = 25
           Top = 29
           Width = 56
@@ -672,12 +542,12 @@ object Form1: TForm1
           Font.Name = 'Arial'
           HasTrackBar = True
           ArrowColor = clBtnText
-          TabOrder = 1
+          TabOrder = 0
           TabStop = True
           UseDockManager = False
         end
         object ButtonPenStyle: TBCButton
-          Left = 37
+          Left = 4
           Height = 25
           Hint = 'Pen style...'
           Top = 1
@@ -848,7 +718,7 @@ object Form1: TForm1
           MemoryUsage = bmuHigh
         end
         object ToolBarJoinStyle: TToolBar
-          Left = 140
+          Left = 107
           Height = 26
           Top = 1
           Width = 74
@@ -857,7 +727,7 @@ object Form1: TForm1
           Images = PenStyleImageList
           ParentShowHint = False
           ShowHint = True
-          TabOrder = 2
+          TabOrder = 1
           object ToolButtonJoinRound: TToolButton
             Left = 3
             Hint = 'Round join'
@@ -892,7 +762,7 @@ object Form1: TForm1
         end
       end
       object PanelBackFill: TBCPanel
-        Left = 285
+        Left = 401
         Height = 60
         Top = 0
         Width = 151
@@ -1014,7 +884,7 @@ object Form1: TForm1
         end
       end
       object PanelShape: TBCPanel
-        Left = 436
+        Left = 552
         Height = 60
         Top = 0
         Width = 122
@@ -1134,7 +1004,7 @@ object Form1: TForm1
         end
       end
       object PanelExtendedStyle: TBCPanel
-        Left = 558
+        Left = 674
         Height = 60
         Top = 0
         Width = 162
@@ -1196,6 +1066,128 @@ object Form1: TForm1
         TabOrder = 4
         Visible = False
       end
+      object PanelPenFill: TBCPanel
+        Left = 65
+        Height = 60
+        Top = 0
+        Width = 151
+        Background.Color = clBtnFace
+        Background.ColorOpacity = 255
+        Background.Gradient1.StartColor = clWhite
+        Background.Gradient1.StartColorOpacity = 255
+        Background.Gradient1.DrawMode = dmSet
+        Background.Gradient1.EndColor = clBlack
+        Background.Gradient1.EndColorOpacity = 255
+        Background.Gradient1.ColorCorrection = True
+        Background.Gradient1.GradientType = gtLinear
+        Background.Gradient1.Point1XPercent = 0
+        Background.Gradient1.Point1YPercent = 0
+        Background.Gradient1.Point2XPercent = 0
+        Background.Gradient1.Point2YPercent = 100
+        Background.Gradient1.Sinus = False
+        Background.Gradient2.StartColor = clWhite
+        Background.Gradient2.StartColorOpacity = 255
+        Background.Gradient2.DrawMode = dmSet
+        Background.Gradient2.EndColor = clBlack
+        Background.Gradient2.EndColorOpacity = 255
+        Background.Gradient2.ColorCorrection = True
+        Background.Gradient2.GradientType = gtLinear
+        Background.Gradient2.Point1XPercent = 0
+        Background.Gradient2.Point1YPercent = 0
+        Background.Gradient2.Point2XPercent = 0
+        Background.Gradient2.Point2YPercent = 100
+        Background.Gradient2.Sinus = False
+        Background.Gradient1EndPercent = 35
+        Background.Style = bbsColor
+        BevelInner = bvNone
+        BevelOuter = bvRaised
+        BevelWidth = 1
+        Border.Color = clBlack
+        Border.ColorOpacity = 255
+        Border.LightColor = clWhite
+        Border.LightOpacity = 255
+        Border.LightWidth = 0
+        Border.Style = bboNone
+        Border.Width = 1
+        FontEx.Color = clDefault
+        FontEx.EndEllipsis = False
+        FontEx.FontQuality = fqFineAntialiasing
+        FontEx.Height = 0
+        FontEx.SingleLine = True
+        FontEx.Shadow = False
+        FontEx.ShadowColor = clBlack
+        FontEx.ShadowColorOpacity = 255
+        FontEx.ShadowRadius = 5
+        FontEx.ShadowOffsetX = 5
+        FontEx.ShadowOffsetY = 5
+        FontEx.Style = []
+        FontEx.TextAlignment = bcaCenter
+        FontEx.WordBreak = False
+        Rounding.RoundX = 1
+        Rounding.RoundY = 1
+        Rounding.RoundOptions = []
+        TabOrder = 5
+        object PanelPenFillHead: TPanel
+          Left = 1
+          Height = 58
+          Top = 1
+          Width = 31
+          Align = alLeft
+          BevelOuter = bvNone
+          ClientHeight = 58
+          ClientWidth = 31
+          TabOrder = 0
+          object LPen: TLabel
+            Left = 0
+            Height = 28
+            Top = 0
+            Width = 31
+            Align = alTop
+            AutoSize = False
+            Caption = 'Pen'
+            Layout = tlCenter
+            ParentColor = False
+            ParentFont = False
+          end
+          object ToolBarPenFill: TToolBar
+            Left = 0
+            Height = 30
+            Top = 28
+            Width = 31
+            Align = alClient
+            ButtonHeight = 28
+            ButtonWidth = 28
+            Caption = 'ToolBarBackFill'
+            EdgeBorders = []
+            EdgeInner = esNone
+            EdgeOuter = esNone
+            Images = VectorImageList24
+            Indent = 0
+            ParentColor = False
+            ParentShowHint = False
+            ShowHint = True
+            TabOrder = 0
+            object ButtonMovePenFillPoints: TToolButton
+              Left = 0
+              Hint = 'Move gradient/texture points'
+              Top = 0
+              Caption = 'ButtonMoveBackFillPoints'
+              ImageIndex = 12
+              OnClick = ToolButtonClick
+              Style = tbsCheck
+            end
+          end
+        end
+        object PenFillControl: TLCVectorialFillControl
+          Left = 32
+          Height = 58
+          Top = 1
+          Width = 117
+          AutoSize = True
+          Align = alLeft
+          ToolIconSize = 24
+        end
+      end
     end
   end
   object ColorDialog1: TColorDialog

+ 125 - 62
vectoredit/umain.pas

@@ -22,12 +22,12 @@ const
                      'Horizontal cylinder', 'Vertical cylinder');
 
 type
-  TPaintTool = (ptHand, ptMoveBackFillPoint, ptRectangle, ptEllipse, ptPolyline, ptCurve, ptPolygon, ptClosedCurve,
+  TPaintTool = (ptHand, ptMovePenFillPoint, ptMoveBackFillPoint, ptRectangle, ptEllipse, ptPolyline, ptCurve, ptPolygon, ptClosedCurve,
                 ptPhongShape);
 
 const
   PaintToolClass : array[TPaintTool] of TVectorShapeAny =
-    (nil, nil, TRectShape, TEllipseShape, TPolylineShape, TCurveShape, TPolylineShape, TCurveShape,
+    (nil, nil, nil, TRectShape, TEllipseShape, TPolylineShape, TCurveShape, TPolylineShape, TCurveShape,
      TPhongShape);
 
 function IsCreateShapeTool(ATool: TPaintTool): boolean;
@@ -40,15 +40,21 @@ type
   { TForm1 }
 
   TForm1 = class(TForm)
+    PenFillControl: TLCVectorialFillControl;
     ButtonMoveBackFillPoints: TToolButton;
+    ButtonMovePenFillPoints: TToolButton;
     LBack: TLabel;
     BackFillControl: TLCVectorialFillControl;
+    LPen: TLabel;
+    PanelPenFill: TBCPanel;
     PanelBackFillHead: TPanel;
+    PanelPenFillHead: TPanel;
     ShapeSendToBack: TAction;
     ShapeBringToFront: TAction;
     ShapeMoveDown: TAction;
     ShapeMoveUp: TAction;
     ToolBarBackFill: TToolBar;
+    ToolBarPenFill: TToolBar;
     VectorImageList24: TBGRAImageList;
     ActionList: TActionList;
     EditCopy: TAction;
@@ -60,7 +66,6 @@ type
     FileSave: TAction;
     FileSaveAs: TAction;
     ButtonPenStyle: TBCButton;
-    Label1: TLabel;
     Label3: TLabel;
     PanelBackFill: TBCPanel;
     PanelBasicStyle: TBCPanel;
@@ -70,7 +75,6 @@ type
     PhongImageList: TBGRAImageList;
     PenStyleImageList: TBGRAImageList;
     CurveImageList: TBGRAImageList;
-    ShapePenColor: TShape;
     ToolBarFile: TToolBar;
     ToolBarEdit: TToolBar;
     ToolBarTop: TToolBar;
@@ -107,7 +111,6 @@ type
     ToolButtonPolygon: TToolButton;
     ToolButtonRectangle: TToolButton;
     ToolButtonEllipse: TToolButton;
-    UpDownPenAlpha: TBCTrackbarUpdown;
     UpDownPenWidth: TBCTrackbarUpdown;
     procedure BCPanelToolbarResize(Sender: TObject);
     procedure BCPanelToolChoiceResize(Sender: TObject);
@@ -142,12 +145,9 @@ type
     procedure FormKeyDown(Sender: TObject; var Key: Word; {%H-}Shift: TShiftState);
     procedure FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
     procedure FormUTF8KeyPress(Sender: TObject; var UTF8Key: TUTF8Char);
-    procedure ShapePenColorMouseUp(Sender: TObject; {%H-}Button: TMouseButton;
-      {%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
     procedure ToolButtonClick(Sender: TObject);
     procedure UpDownPenAlphaChange(Sender: TObject; AByUser: boolean);
   private
-    FPenColor: TBGRAPixel;
     FPenWidth: single;
     FPenStyle: TBGRAPenStyle;
     FPenJoinStyle: TPenJoinStyle;
@@ -168,7 +168,6 @@ type
     FUpDownPhongBorderSize: TBCTrackbarUpdown;
     FInRemoveShapeIfEmpty: Boolean;
     procedure ComboBoxSplineStyleClick(Sender: TObject);
-    function GetPenColor: TBGRAPixel;
     function GetPenStyle: TBGRAPenStyle;
     function GetPenWidth: single;
     function GetSplineStyle: TSplineStyle;
@@ -187,7 +186,6 @@ type
     procedure RequestBackFillUpdate(Sender: TObject);
     procedure OnBackFillChange({%H-}ASender: TObject);
     procedure SetCurrentTool(AValue: TPaintTool);
-    procedure SetPenColor(AValue: TBGRAPixel);
     procedure SetPenJoinStyle(AValue: TPenJoinStyle);
     procedure SetPenStyle(AValue: TBGRAPenStyle);
     procedure SetPenWidth(AValue: single);
@@ -204,13 +202,18 @@ type
     function CreateShape(const APoint1, APoint2: TPointF): TVectorShape;
     procedure RemoveExtendedStyleControls;
     procedure UpdateBackToolFillPoints;
+    procedure UpdatePenToolFillPoints;
     procedure UpdateShapeBackFill;
+    procedure UpdateShapePenFill;
     procedure UpdateShapeUserMode;
     procedure UpdateShapeActions(AShape: TVectorShape);
     procedure RemoveShapeIfEmpty(AShape: TVectorShape);
     function VirtualScreenToImgCoord(X,Y: Integer): TPointF;
     procedure SetEditorGrid(AActive: boolean);
     procedure RequestBackFillAdjustToShape(Sender: TObject);
+    procedure PenFillControlResize(Sender: TObject);
+    procedure RequestPenFillAdjustToShape(Sender: TObject);
+    procedure RequestPenFillUpdate(Sender: TObject);
   public
     { public declarations }
     img: TBGRALazPaintImage;
@@ -229,7 +232,6 @@ type
     procedure DoPaste;
     procedure DoDelete;
     property vectorTransform: TAffineMatrix read GetVectorTransform;
-    property penColor: TBGRAPixel read GetPenColor write SetPenColor;
     property penWidth: single read GetPenWidth write SetPenWidth;
     property penStyle: TBGRAPenStyle read GetPenStyle write SetPenStyle;
     property splineStyle: TSplineStyle read GetSplineStyle write SetSplineStyle;
@@ -332,8 +334,18 @@ begin
     FPenStyleMenu.Items.Add(item);
   end;
 
+  PenFillControl.ToolIconSize:= ActionIconSize;
+  PenFillControl.SolidColor := BGRABlack;
+  PenFillControl.GradStartColor := BGRAWhite;
+  PenFillControl.GradEndColor := BGRABlack;
+  PenFillControl.OnFillChange:=@RequestPenFillUpdate;
+  PenFillControl.OnAdjustToShape:=@RequestPenFillAdjustToShape;
+  PenFillControl.OnResize:=@PenFillControlResize;
+
   BackFillControl.ToolIconSize:= ActionIconSize;
   BackFillControl.SolidColor := CSSDodgerBlue;
+  BackFillControl.GradStartColor := MergeBGRA(CSSDodgerBlue,BGRAWhite);
+  BackFillControl.GradEndColor := MergeBGRA(CSSDodgerBlue,BGRABlack);
   BackFillControl.OnFillChange:= @RequestBackFillUpdate;
   BackFillControl.OnAdjustToShape:= @RequestBackFillAdjustToShape;
   BackFillControl.OnResize:= @BackFillControlResize;
@@ -348,7 +360,6 @@ begin
   end;
 
   newShape:= nil;
-  penColor := BGRABlack;
   penWidth := 5;
   penStyle := SolidPenStyle;
   joinStyle:= pjsBevel;
@@ -358,6 +369,7 @@ begin
   FPhongBorderSize := DefaultPhongBorderSizePercent;
   UpdateTitleBar;
   UpdateBackToolFillPoints;
+  UpdatePenToolFillPoints;
   UpdateShapeActions(nil);
 end;
 
@@ -629,6 +641,12 @@ begin
       newShape.BackFill := vectorFill;
       vectorFill.Free;
     end;
+    if (vsfPenFill in newShape.Fields) and (newShape.PenFill.FillType in [vftGradient, vftTexture]) then
+    begin
+      vectorFill := PenFillControl.CreateShapeFill(newShape);
+      newShape.PenFill := vectorFill;
+      vectorFill.Free;
+    end;
     rF := newShape.GetRenderBounds(InfiniteRect, vectorTransform);
     ImageChange(rF.Union(prevRF, true));
   end;
@@ -738,26 +756,24 @@ begin
   end;
 end;
 
-procedure TForm1.ShapePenColorMouseUp(Sender: TObject; Button: TMouseButton;
-  Shift: TShiftState; X, Y: Integer);
-begin
-  ColorDialog1.Color := ShapePenColor.Brush.Color;
-  if ColorDialog1.Execute then
-  begin
-    if penColor.alpha <> 0 then
-      penColor := ColorToBGRA(ColorDialog1.Color, penColor.alpha)
-    else
-      penColor := ColorDialog1.Color;
-  end;
-end;
-
 procedure TForm1.ToolButtonClick(Sender: TObject);
 begin
   if Sender = ButtonMoveBackFillPoints then
-    if ButtonMoveBackFillPoints.Down then ToolButtonMove.Down := true;
+    if ButtonMoveBackFillPoints.Down then
+    begin
+      ToolButtonMove.Down := true;
+      ButtonMovePenFillPoints.Down := false;
+    end;
+  if Sender = ButtonMovePenFillPoints then
+    if ButtonMovePenFillPoints.Down then
+    begin
+      ToolButtonMove.Down := true;
+      ButtonMoveBackFillPoints.Down := false;
+    end;
 
   FCurrentTool := ptHand;
   if ButtonMoveBackFillPoints.Down then FCurrentTool:= ptMoveBackFillPoint;
+  if ButtonMovePenFillPoints.Down then FCurrentTool:= ptMovePenFillPoint;
   if ToolButtonEllipse.Down then FCurrentTool:= ptEllipse;
   if ToolButtonRectangle.Down then FCurrentTool:= ptRectangle;
   if ToolButtonPolyline.Down then FCurrentTool:= ptPolyline;
@@ -766,8 +782,8 @@ begin
   if ToolButtonClosedCurve.Down then FCurrentTool:= ptClosedCurve;
   if ToolButtonPhongShape.Down then FCurrentTool:= ptPhongShape;
 
-  if currentTool <> ptMoveBackFillPoint then
-    ButtonMoveBackFillPoints.Down := false;
+  if currentTool <> ptMoveBackFillPoint then ButtonMoveBackFillPoints.Down := false;
+  if currentTool <> ptMovePenFillPoint then ButtonMovePenFillPoints.Down := false;
 
   if IsCreateShapeTool(currentTool) then
   begin
@@ -786,12 +802,7 @@ end;
 
 procedure TForm1.UpDownPenAlphaChange(Sender: TObject; AByUser: boolean);
 begin
-  if AByUser then
-  begin
-    FPenColor:= ColorToBGRA(ShapePenColor.Brush.Color, UpDownPenAlpha.Value);
-    if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) then
-      vectorOriginal.SelectedShape.PenColor:= FPenColor;
-  end;
+
 end;
 
 procedure TForm1.ComboBoxSplineStyleClick(Sender: TObject);
@@ -801,11 +812,6 @@ begin
       FSplineStyleMenu.PopUp(X,Y);
 end;
 
-function TForm1.GetPenColor: TBGRAPixel;
-begin
-  result := FPenColor;
-end;
-
 function TForm1.GetPenStyle: TBGRAPenStyle;
 begin
   result := FPenStyle;
@@ -892,13 +898,23 @@ procedure TForm1.OnSelectShape(ASender: TObject; AShape: TVectorShape;
 begin
   if ASender <> vectorOriginal then exit;
   UpdateToolbarFromShape(AShape);
-  if currentTool = ptMoveBackFillPoint then
-  begin
-    if Assigned(AShape) and (vsuEditBackFill in AShape.Usermodes) and
-       AShape.BackFill.IsEditable then
-      AShape.Usermode:= vsuEditBackFill
-    else
-      currentTool:= ptHand;
+  case currentTool of
+    ptMoveBackFillPoint:
+    begin
+      if Assigned(AShape) and (vsuEditBackFill in AShape.Usermodes) and
+         AShape.BackFill.IsEditable then
+        AShape.Usermode:= vsuEditBackFill
+      else
+        currentTool:= ptHand;
+    end;
+    ptMovePenFillPoint:
+    begin
+      if Assigned(AShape) and (vsuEditPenFill in AShape.Usermodes) and
+         AShape.PenFill.IsEditable then
+        AShape.Usermode:= vsuEditPenFill
+      else
+        currentTool:= ptHand;
+    end;
   end;
 
   UpdateShapeActions(AShape);
@@ -950,21 +966,10 @@ begin
   ToolButtonCurve.Down := FCurrentTool = ptCurve;
   ToolButtonPhongShape.Down:= FCurrentTool = ptPhongShape;
   ButtonMoveBackFillPoints.Down := FCurrentTool = ptMoveBackFillPoint;
+  ButtonMovePenFillPoints.Down := FCurrentTool = ptMovePenFillPoint;
   UpdateShapeUserMode;
 end;
 
-procedure TForm1.SetPenColor(AValue: TBGRAPixel);
-begin
-  FPenColor := AValue;
-  ShapePenColor.Brush.Color := BGRA(AValue.red,AValue.green,AValue.blue).ToColor;
-  UpDownPenAlpha.Value := AValue.alpha;
-  if not FUpdatingFromShape and Assigned(vectorOriginal) then
-  begin
-    if Assigned(vectorOriginal.SelectedShape) then
-      vectorOriginal.SelectedShape.PenColor := AValue;
-  end;
-end;
-
 procedure TForm1.SetPenJoinStyle(AValue: TPenJoinStyle);
 begin
   if FPenJoinStyle=AValue then Exit;
@@ -1169,7 +1174,7 @@ begin
     FUpdatingFromShape := true;
     mode := AShape.Usermode;
     f := AShape.Fields;
-    if vsfPenColor in f then penColor := AShape.PenColor;
+    if vsfPenFill in f then PenFillControl.AssignFill(AShape.PenFill);
     if vsfPenWidth in f then penWidth:= AShape.PenWidth;
     if vsfPenStyle in f then penStyle:= AShape.PenStyle;
     if vsfJoinStyle in f then joinStyle:= AShape.JoinStyle;
@@ -1210,6 +1215,7 @@ begin
     end;
   end;
   UpdateBackToolFillPoints;
+  UpdatePenToolFillPoints;
   UpDownPenWidth.Enabled := vsfPenWidth in f;
   ButtonPenStyle.Enabled:= vsfPenStyle in f;
   EnableDisableToolButtons([ToolButtonJoinRound,ToolButtonJoinBevel,ToolButtonJoinMiter], vsfJoinStyle in f);
@@ -1312,7 +1318,7 @@ begin
     raise exception.Create('No shape type selected');
   result := PaintToolClass[currentTool].Create(vectorOriginal);
   if (result is TCustomPolypointShape) and (BackFillControl.FillType = vftGradient) then BackFillControl.FillType := vftSolid;
-  result.PenColor := penColor;
+  if (result is TCustomPolypointShape) and (PenFillControl.FillType = vftGradient) then PenFillControl.FillType := vftSolid;
   result.PenWidth := penWidth;
   result.PenStyle := penStyle;
   if vsfJoinStyle in result.Fields then result.JoinStyle := joinStyle;
@@ -1335,6 +1341,12 @@ begin
     result.BackFill := vectorFill;
     vectorFill.Free;
   end;
+  if vsfPenFill in result.Fields then
+  begin
+    vectorFill := PenFillControl.CreateShapeFill(result);
+    result.PenFill := vectorFill;
+    vectorFill.Free;
+  end;
 end;
 
 procedure TForm1.RemoveExtendedStyleControls;
@@ -1376,11 +1388,28 @@ begin
   if (currentTool = ptMoveBackFillPoint) and not canEdit then currentTool:= ptHand;
 end;
 
+procedure TForm1.UpdatePenToolFillPoints;
+var
+  canEdit: Boolean;
+begin
+  canEdit := (PenFillControl.FillType in[vftGradient,vftTexture]) and
+    Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape);
+  ButtonMovePenFillPoints.Enabled := canEdit;
+  if (currentTool = ptMovePenFillPoint) and not canEdit then currentTool:= ptHand;
+end;
+
 procedure TForm1.UpdateShapeBackFill;
 begin
   if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
     (vsfBackFill in vectorOriginal.SelectedShape.Fields) then
-    BackFillControl.UpdateShapeFill(vectorOriginal.SelectedShape);
+    BackFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, True);
+end;
+
+procedure TForm1.UpdateShapePenFill;
+begin
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
+    (vsfPenFill in vectorOriginal.SelectedShape.Fields) then
+    PenFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, FAlse);
 end;
 
 procedure TForm1.UpdateShapeUserMode;
@@ -1394,8 +1423,15 @@ begin
       if vectorOriginal.SelectedShape.Usermode <> vsuEditBackFill then
         vectorOriginal.SelectedShape.Usermode := vsuEditBackFill;
     end else
+    if (currentTool = ptMovePenFillPoint) and
+       (vsfPenFill in vectorOriginal.SelectedShape.Fields) and
+       vectorOriginal.SelectedShape.PenFill.IsEditable then
+    begin
+      if vectorOriginal.SelectedShape.Usermode <> vsuEditPenFill then
+        vectorOriginal.SelectedShape.Usermode := vsuEditPenFill;
+    end else
     begin
-      if vectorOriginal.SelectedShape.Usermode = vsuEditBackFill then
+      if vectorOriginal.SelectedShape.Usermode in[vsuEditPenFill,vsuEditBackFill] then
         vectorOriginal.SelectedShape.Usermode := vsuEdit;
     end;
   end;
@@ -1411,6 +1447,7 @@ begin
   EditCut.Enabled := AShape <> nil;
   EditDelete.Enabled := AShape <> nil;
   BackFillControl.CanAdjustToShape := AShape <> nil;
+  PenFillControl.CanAdjustToShape := AShape <> nil;
 end;
 
 procedure TForm1.RemoveShapeIfEmpty(AShape: TVectorShape);
@@ -1469,6 +1506,32 @@ begin
   end;
 end;
 
+procedure TForm1.PenFillControlResize(Sender: TObject);
+begin
+  PanelPenFill.ClientWidth := PanelPenFillHead.Width+PenFillControl.Width+2;
+end;
+
+procedure TForm1.RequestPenFillAdjustToShape(Sender: TObject);
+var
+  vectorFill: TVectorialFill;
+begin
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) then
+  begin
+    vectorFill := PenFillControl.CreateShapeFill(vectorOriginal.SelectedShape);
+    vectorOriginal.SelectedShape.PenFill := vectorFill;
+    vectorFill.Free;
+  end;
+end;
+
+procedure TForm1.RequestPenFillUpdate(Sender: TObject);
+begin
+  if not FUpdatingFromShape then
+  begin
+    UpdateShapePenFill;
+    UpdatePenToolFillPoints;
+  end;
+end;
+
 procedure TForm1.DoCopy;
 begin
   if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) then