Explorar o código

add outline fill interface

Unknown %!s(int64=6) %!d(string=hai) anos
pai
achega
2047c605ae

+ 11 - 3
lazpaintcontrols/lcvectorialfillcontrol.pas

@@ -9,6 +9,14 @@ uses
   LCVectorialFill, BGRABitmap, BGRABitmapTypes, BGRAGradientScanner,
   LCVectorOriginal;
 
+type
+  TLCFillTarget = LCVectorialFillInterface.TLCFillTarget;
+
+const
+  ftPen = LCVectorialFillInterface.ftPen;
+  ftBack = LCVectorialFillInterface.ftBack;
+  ftOutline = LCVectorialFillInterface.ftOutline;
+
 type
   { TLCVectorialFillControl }
 
@@ -56,7 +64,7 @@ type
     destructor Destroy; override;
     procedure AssignFill(AFill: TVectorialFill);
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
-    procedure UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
+    procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     property FillType: TVectorialFillType read GetFillType write SetFillType;
     property SolidColor: TBGRAPixel read GetSolidColor write SetSolidColor;
     property GradientType: TGradientType read GetGradType write SetGradientType;
@@ -283,9 +291,9 @@ begin
 end;
 
 procedure TLCVectorialFillControl.UpdateShapeFill(AShape: TVectorShape;
-  ABackFill: boolean);
+  ATarget: TLCFillTarget);
 begin
-  FInterface.UpdateShapeFill(AShape, ABackFill);
+  FInterface.UpdateShapeFill(AShape, ATarget);
 end;
 
 end.

+ 14 - 10
lazpaintcontrols/lcvectorialfillinterface.pas

@@ -17,6 +17,7 @@ const
   TextureRepetitionToStr: array[TTextureRepetition] of string = ('No repetition', 'Repeat X', 'Repeat Y', 'Repeat both');
 
 type
+  TLCFillTarget = (ftPen, ftBack, ftOutline);
 
   { TVectorialFillInterface }
 
@@ -129,7 +130,7 @@ type
     function GetTextureThumbnail(AWidth, AHeight: integer; ABackColor: TColor): TBitmap;
     procedure AssignFill(AFill: TVectorialFill);
     function CreateShapeFill(AShape: TVectorShape): TVectorialFill;
-    procedure UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
+    procedure UpdateShapeFill(AShape: TVectorShape; ATarget: TLCFillTarget);
     property FillType: TVectorialFillType read FFillType write SetFillType;
     property SolidColor: TBGRAPixel read FSolidColor write SetSolidColor;
     property GradientType: TGradientType read FGradType write SetGradientType;
@@ -918,15 +919,17 @@ begin
   else result := nil; //none
 end;
 
-procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape; ABackFill: boolean);
+procedure TVectorialFillInterface.UpdateShapeFill(AShape: TVectorShape;
+  ATarget: TLCFillTarget);
 var
   vectorFill: TVectorialFill;
   curFill: TVectorialFill;
 begin
-  if ABackFill then
-    curFill:= AShape.BackFill
-  else
-    curFill:= AShape.PenFill;
+  case ATarget of
+    ftPen: curFill:= AShape.PenFill;
+    ftBack: curFill := AShape.BackFill;
+    ftOutline: curFill := AShape.OutlineFill;
+  end;
 
   if (FillType = vftTexture) and (TextureOpacity = 0) then
     vectorFill := nil else
@@ -946,10 +949,11 @@ begin
   end else
     vectorFill := CreateShapeFill(AShape);
 
-  if ABackFill then
-    AShape.BackFill:= vectorFill
-  else
-    AShape.PenFill:= vectorFill;
+  case ATarget of
+    ftPen: AShape.PenFill:= vectorFill;
+    ftBack: AShape.BackFill:= vectorFill;
+    ftOutline: AShape.OutlineFill:= vectorFill;
+  end;
   vectorFill.Free;
 end;
 

+ 71 - 53
lazpaintcontrols/lcvectororiginal.pas

@@ -21,9 +21,9 @@ type
 
   TRenderBoundsOption = (rboAssumePenFill, rboAssumeBackFill);
   TRenderBoundsOptions = set of TRenderBoundsOption;
-  TVectorShapeField = (vsfPenFill, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill);
+  TVectorShapeField = (vsfPenFill, vsfPenWidth, vsfPenStyle, vsfJoinStyle, vsfBackFill, vsfOutlineFill);
   TVectorShapeFields = set of TVectorShapeField;
-  TVectorShapeUsermode = (vsuEdit, vsuCreate, vsuEditPenFill, vsuEditBackFill,
+  TVectorShapeUsermode = (vsuEdit, vsuCreate, vsuEditPenFill, vsuEditBackFill, vsuEditOutlineFill,
                           vsuCurveSetAuto, vsuCurveSetCurve, vsuCurveSetAngle,
                           vsuEditText);
   TVectorShapeUsermodes = set of TVectorShapeUsermode;
@@ -36,7 +36,7 @@ type
     FOnEditingChange: TShapeEditingChangeEvent;
     FUpdateCount: integer;
     FBoundsBeforeUpdate: TRectF;
-    FPenFill, FBackFill: TVectorialFill;
+    FPenFill, FBackFill, FOutlineFill: TVectorialFill;
     FPenWidth: single;
     FStroker: TBGRAPenStroker;
     FUsermode: TVectorShapeUsermode;
@@ -45,6 +45,8 @@ type
     function GetIsBack: boolean;
     function GetIsFront: boolean;
     procedure SetContainer(AValue: TVectorOriginal);
+    function GetFill(var AFillVariable: TVectorialFill): TVectorialFill;
+    procedure SetFill(var AFillVariable: TVectorialFill; AValue: TVectorialFill);
   protected
     procedure BeginUpdate;
     procedure EndUpdate;
@@ -54,12 +56,14 @@ type
     function GetJoinStyle: TPenJoinStyle;
     function GetBackFill: TVectorialFill; virtual;
     function GetPenFill: TVectorialFill; virtual;
+    function GetOutlineFill: 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 SetOutlineFill(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);
@@ -101,6 +105,7 @@ type
     property PenColor: TBGRAPixel read GetPenColor write SetPenColor;
     property PenFill: TVectorialFill read GetPenFill write SetPenFill;
     property BackFill: TVectorialFill read GetBackFill write SetBackFill;
+    property OutlineFill: TVectorialFill read GetOutlineFill write SetOutlineFill;
     property PenWidth: single read GetPenWidth write SetPenWidth;
     property PenStyle: TBGRAPenStyle read GetPenStyle write SetPenStyle;
     property JoinStyle: TPenJoinStyle read GetJoinStyle write SetJoinStyle;
@@ -491,6 +496,11 @@ begin
     result[nb] := PenFill.Texture;
     inc(nb);
   end;
+  if (vsfOutlineFill in f) and (OutlineFill.FillType = vftTexture) then
+  begin
+    result[nb] := OutlineFill.Texture;
+    inc(nb);
+  end;
   setlength(result, nb);
 end;
 
@@ -637,6 +647,7 @@ begin
   result := [vsuEdit];
   if vsfBackFill in Fields then result += [vsuEditBackFill];
   if vsfPenFill in Fields then result += [vsuEditPenFill];
+  if vsfOutlineFill in Fields then result += [vsuEditOutlineFill];
 end;
 
 class function TVectorShape.PreferPixelCentered: boolean;
@@ -656,6 +667,45 @@ begin
   FContainer:=AValue;
 end;
 
+function TVectorShape.GetFill(var AFillVariable: TVectorialFill): TVectorialFill;
+begin
+  if AFillVariable = nil then
+  begin
+    AFillVariable := TVectorialFill.Create;
+    AFillVariable.OnChange := @FillChange;
+  end;
+  result := AFillVariable;
+end;
+
+procedure TVectorShape.SetFill(var AFillVariable: TVectorialFill;
+  AValue: TVectorialFill);
+var
+  sharedTex: TBGRABitmap;
+  freeTex: Boolean;
+begin
+  if AFillVariable.Equals(AValue) then exit;
+  BeginUpdate;
+  freeTex := Assigned(AFillVariable) and Assigned(AFillVariable.Texture) and
+    not (Assigned(AValue) and (AValue.FillType = vftTexture) and (AValue.Texture = AFillVariable.Texture));
+  if AValue = nil then FreeAndNil(AFillVariable) else
+  if AValue.FillType = vftTexture then
+  begin
+    if Assigned(Container) then
+      sharedTex := Container.GetTexture(Container.AddTexture(AValue.Texture))
+    else
+      sharedTex := AValue.Texture;
+    GetFill(AFillVariable).SetTexture(sharedTex, AValue.TextureMatrix, AValue.TextureOpacity, AValue.TextureRepetition);
+  end else
+    GetFill(AFillVariable).Assign(AValue);
+  if Assigned(Container) and freeTex then Container.DiscardUnusedTextures;
+  EndUpdate;
+end;
+
+procedure TVectorShape.SetOutlineFill(AValue: TVectorialFill);
+begin
+  SetFill(FOutlineFill, AValue);
+end;
+
 function TVectorShape.GetIsBack: boolean;
 begin
   result := Assigned(Container) and (Container.IndexOfShape(self)=0);
@@ -666,6 +716,11 @@ begin
   result := Assigned(Container) and (Container.IndexOfShape(self)=Container.ShapeCount-1);
 end;
 
+function TVectorShape.GetOutlineFill: TVectorialFill;
+begin
+  result := GetFill(FOutlineFill);
+end;
+
 procedure TVectorShape.BeginUpdate;
 begin
   if FUpdateCount = 0 then
@@ -711,22 +766,12 @@ end;
 
 function TVectorShape.GetBackFill: TVectorialFill;
 begin
-  if FBackFill = nil then
-  begin
-    FBackFill := TVectorialFill.Create;
-    FBackFill.OnChange := @FillChange;
-  end;
-  result := FBackFill;
+  result := GetFill(FBackFill);
 end;
 
 function TVectorShape.GetPenFill: TVectorialFill;
 begin
-  if FPenFill = nil then
-  begin
-    FPenFill := TVectorialFill.Create;
-    FPenFill.OnChange := @FillChange;
-  end;
-  result := FPenFill;
+  result := GetFill(FPenFill);
 end;
 
 function TVectorShape.ComputeStroke(APoints: ArrayOfTPointF; AClosed: boolean; AStrokeMatrix: TAffineMatrix): ArrayOfTPointF;
@@ -780,49 +825,13 @@ begin
 end;
 
 procedure TVectorShape.SetBackFill(AValue: TVectorialFill);
-var
-  sharedTex: TBGRABitmap;
-  freeTex: Boolean;
 begin
-  if FBackFill.Equals(AValue) then exit;
-  BeginUpdate;
-  freeTex := Assigned(FBackFill) and Assigned(FBackFill.Texture) and
-    not (Assigned(AValue) and (AValue.FillType = vftTexture) and (AValue.Texture = FBackFill.Texture));
-  if AValue = nil then FreeAndNil(FBackFill) else
-  if AValue.FillType = vftTexture then
-  begin
-    if Assigned(Container) then
-      sharedTex := Container.GetTexture(Container.AddTexture(AValue.Texture))
-    else
-      sharedTex := AValue.Texture;
-    BackFill.SetTexture(sharedTex, AValue.TextureMatrix, AValue.TextureOpacity, AValue.TextureRepetition);
-  end else
-    BackFill.Assign(AValue);
-  if Assigned(Container) and freeTex then Container.DiscardUnusedTextures;
-  EndUpdate;
+  SetFill(FBackFill, AValue);
 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;
+  SetFill(FPenFill, AValue);
 end;
 
 constructor TVectorShape.Create(AContainer: TVectorOriginal);
@@ -834,6 +843,7 @@ begin
   FOnChange := nil;
   FOnEditingChange := nil;
   FBackFill := nil;
+  FOutlineFill := nil;
   FUsermode:= vsuEdit;
   FRemoving:= false;
 end;
@@ -843,6 +853,7 @@ begin
   FreeAndNil(FStroker);
   FreeAndNil(FPenFill);
   FreeAndNil(FBackFill);
+  FreeAndNil(FOutlineFill);
   inherited Destroy;
 end;
 
@@ -864,6 +875,7 @@ begin
       else JoinStyle := pjsMiter;
       end;
     if vsfBackFill in f then LoadFill(AStorage, 'back', FBackFill);
+    if vsfOutlineFill in f then LoadFill(AStorage, 'outline', FOutlineFill);
     EndUpdate;
   end;
 end;
@@ -883,6 +895,7 @@ begin
     else AStorage.RawString['join-style'] := 'miter';
     end;
   if vsfBackFill in f then SaveFill(AStorage, 'back', FBackFill);
+  if vsfOutlineFill in f then SaveFill(AStorage, 'outline', FOutlineFill);
 end;
 
 procedure TVectorShape.MouseMove(Shift: TShiftState; X, Y: single; var
@@ -1254,6 +1267,8 @@ begin
        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;
+    if Assigned(AShape) and (prevMode = vsuEditOutlineFill) and (prevMode in AShape.Usermodes) and
+       AShape.OutlineFill.IsEditable then AShape.Usermode:= prevMode;
     if Assigned(AShape) and (prevMode = vsuEditText) and (prevMode in AShape.Usermodes) then
       AShape.Usermode := prevMode;
     FSelectedShape := AShape;
@@ -1348,6 +1363,9 @@ begin
       else
       if (FSelectedShape.Usermode = vsuEditPenFill) and FSelectedShape.PenFill.IsEditable then
         FSelectedShape.PenFill.ConfigureEditor(AEditor)
+      else
+      if (FSelectedShape.Usermode = vsuEditOutlineFill) and FSelectedShape.OutlineFill.IsEditable then
+        FSelectedShape.OutlineFill.ConfigureEditor(AEditor)
       else
         FSelectedShape.ConfigureEditor(AEditor);
     end;

+ 132 - 7
vectoredit/umain.lfm

@@ -452,6 +452,7 @@ object Form1: TForm1
           object LPen: TLabel
             Left = 0
             Height = 28
+            Hint = 'Pen color'
             Top = 0
             Width = 31
             Align = alTop
@@ -460,6 +461,8 @@ object Form1: TForm1
             Layout = tlCenter
             ParentColor = False
             ParentFont = False
+            ParentShowHint = False
+            ShowHint = True
           end
           object ToolBarPenFill: TToolBar
             Left = 0
@@ -469,7 +472,6 @@ object Form1: TForm1
             Align = alClient
             ButtonHeight = 28
             ButtonWidth = 28
-            Caption = 'ToolBarBackFill'
             EdgeBorders = []
             EdgeInner = esNone
             EdgeOuter = esNone
@@ -483,7 +485,6 @@ object Form1: TForm1
               Left = 0
               Hint = 'Move gradient/texture points'
               Top = 0
-              Caption = 'ButtonMoveBackFillPoints'
               ImageIndex = 12
               OnClick = ToolButtonClick
               Style = tbsCheck
@@ -973,6 +974,7 @@ object Form1: TForm1
           object LBack: TLabel
             Left = 0
             Height = 28
+            Hint = 'Back color'
             Top = 0
             Width = 31
             Align = alTop
@@ -981,6 +983,8 @@ object Form1: TForm1
             Layout = tlCenter
             ParentColor = False
             ParentFont = False
+            ParentShowHint = False
+            ShowHint = True
           end
           object ToolBarBackFill: TToolBar
             Left = 0
@@ -990,7 +994,6 @@ object Form1: TForm1
             Align = alClient
             ButtonHeight = 28
             ButtonWidth = 28
-            Caption = 'ToolBarBackFill'
             EdgeBorders = []
             EdgeInner = esNone
             EdgeOuter = esNone
@@ -1004,7 +1007,6 @@ object Form1: TForm1
               Left = 0
               Hint = 'Move gradient/texture points'
               Top = 0
-              Caption = 'ButtonMoveBackFillPoints'
               ImageIndex = 12
               OnClick = ToolButtonClick
               Style = tbsCheck
@@ -1022,7 +1024,7 @@ object Form1: TForm1
         end
       end
       object PanelShape: TBCPanel
-        Left = 549
+        Left = 700
         Height = 59
         Top = 0
         Width = 120
@@ -1142,9 +1144,9 @@ object Form1: TForm1
         end
       end
       object PanelExtendedStyle: TBCPanel
-        Left = 669
+        Left = 0
         Height = 59
-        Top = 0
+        Top = 59
         Width = 162
         Background.Color = clBtnFace
         Background.ColorOpacity = 255
@@ -1204,6 +1206,129 @@ object Form1: TForm1
         TabOrder = 4
         Visible = False
       end
+      object PanelOutlineFill: TBCPanel
+        Left = 549
+        Height = 59
+        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 = 6
+        object PanelOutlineFillHead: TPanel
+          Left = 1
+          Height = 57
+          Top = 1
+          Width = 31
+          Align = alLeft
+          BevelOuter = bvNone
+          ClientHeight = 57
+          ClientWidth = 31
+          TabOrder = 0
+          object LOutline: TLabel
+            Left = 0
+            Height = 28
+            Hint = 'Outline color'
+            Top = 0
+            Width = 31
+            Align = alTop
+            AutoSize = False
+            Caption = 'Out'
+            Layout = tlCenter
+            ParentColor = False
+            ParentFont = False
+            ParentShowHint = False
+            ShowHint = True
+          end
+          object ToolBarOutlineFill: TToolBar
+            Left = 0
+            Height = 29
+            Top = 28
+            Width = 31
+            Align = alClient
+            ButtonHeight = 28
+            ButtonWidth = 28
+            EdgeBorders = []
+            EdgeInner = esNone
+            EdgeOuter = esNone
+            Images = VectorImageList24
+            Indent = 0
+            ParentColor = False
+            ParentShowHint = False
+            ShowHint = True
+            TabOrder = 0
+            object ButtonMoveOutlineFillPoints: TToolButton
+              Left = 0
+              Hint = 'Move gradient/texture points'
+              Top = 0
+              ImageIndex = 12
+              OnClick = ToolButtonClick
+              Style = tbsCheck
+            end
+          end
+        end
+        object OutlineFillControl: TLCVectorialFillControl
+          Left = 32
+          Height = 57
+          Top = 1
+          Width = 117
+          AutoSize = True
+          Align = alLeft
+          ToolIconSize = 24
+        end
+      end
     end
   end
   object ColorDialog1: TColorDialog

+ 115 - 7
vectoredit/umain.pas

@@ -22,12 +22,12 @@ const
                      'Horizontal cylinder', 'Vertical cylinder');
 
 type
-  TPaintTool = (ptHand, ptMovePenFillPoint, ptMoveBackFillPoint, ptRectangle, ptEllipse, ptPolyline, ptCurve, ptPolygon, ptClosedCurve,
+  TPaintTool = (ptHand, ptMovePenFillPoint, ptMoveBackFillPoint, ptMoveOutlineFillPoint, ptRectangle, ptEllipse, ptPolyline, ptCurve, ptPolygon, ptClosedCurve,
                 ptPhongShape, ptText);
 
 const
   PaintToolClass : array[TPaintTool] of TVectorShapeAny =
-    (nil, nil, nil, TRectShape, TEllipseShape, TPolylineShape, TCurveShape, TPolylineShape, TCurveShape,
+    (nil, nil, nil, nil, TRectShape, TEllipseShape, TPolylineShape, TCurveShape, TPolylineShape, TCurveShape,
      TPhongShape, TTextShape);
 
 function IsCreateShapeTool(ATool: TPaintTool): boolean;
@@ -43,6 +43,11 @@ type
   { TForm1 }
 
   TForm1 = class(TForm)
+    OutlineFillControl: TLCVectorialFillControl;
+    ButtonMoveOutlineFillPoints: TToolButton;
+    LOutline: TLabel;
+    PanelOutlineFill: TBCPanel;
+    PanelOutlineFillHead: TPanel;
     PenFillControl: TLCVectorialFillControl;
     ButtonMoveBackFillPoints: TToolButton;
     ButtonMovePenFillPoints: TToolButton;
@@ -57,6 +62,7 @@ type
     ShapeMoveDown: TAction;
     ShapeMoveUp: TAction;
     ToolBarBackFill: TToolBar;
+    ToolBarOutlineFill: TToolBar;
     ToolBarPenFill: TToolBar;
     ToolButtonTextShape: TToolButton;
     VectorImageList24: TBGRAImageList;
@@ -130,6 +136,7 @@ type
     procedure FileSaveAsExecute(Sender: TObject);
     procedure FileSaveExecute(Sender: TObject);
     procedure BackFillControlResize(Sender: TObject);
+    procedure OutlineFillControlResize(Sender: TObject);
     procedure PanelFileResize(Sender: TObject);
     procedure PanelShapeResize(Sender: TObject);
    procedure ShapeBringToFrontExecute(Sender: TObject);
@@ -207,6 +214,7 @@ type
     procedure OnClickPenStyle(ASender: TObject);
     procedure PhongShapeKindClick(Sender: TObject);
     procedure RequestBackFillUpdate(Sender: TObject);
+    procedure RequestOutlineFillUpdate(Sender: TObject);
     procedure OnBackFillChange({%H-}ASender: TObject);
     procedure SetCurrentTool(AValue: TPaintTool);
     procedure SetPenJoinStyle(AValue: TPenJoinStyle);
@@ -228,8 +236,10 @@ type
     procedure RemoveExtendedStyleControls;
     procedure UpdateBackToolFillPoints;
     procedure UpdatePenToolFillPoints;
+    procedure UpdateOutlineToolFillPoints;
     procedure UpdateShapeBackFill;
     procedure UpdateShapePenFill;
+    procedure UpdateShapeOutlineFill;
     procedure UpdateShapeUserMode;
     procedure UpdateShapeActions(AShape: TVectorShape);
     procedure RemoveShapeIfEmpty(AShape: TVectorShape);
@@ -239,6 +249,7 @@ type
     procedure PenFillControlResize(Sender: TObject);
     procedure RequestPenFillAdjustToShape(Sender: TObject);
     procedure RequestPenFillUpdate(Sender: TObject);
+    procedure RequestOutlineFillAdjustToShape(Sender: TObject);
     procedure AdjustToolbarTop;
     procedure UpdateSplineToolbar;
     function SnapToGrid(APoint: TPointF): TPointF;
@@ -303,6 +314,7 @@ begin
   ToolbarTop.ButtonHeight:= 2*FFullIconHeight+3;
   LBack.Height := FFullIconHeight;
   LPen.Height := FFullIconHeight;
+  LOutline.Height := FFullIconHeight;
 
   if VectorImageList24.Height = ActionIconSize then
   begin
@@ -323,6 +335,7 @@ begin
   SetToolbarImages(ToolBarEdit, FVectorImageList);
   SetToolBarImages(ToolBarBackFill, FVectorImageList);
   SetToolBarImages(ToolBarPenFill, FVectorImageList);
+  SetToolBarImages(ToolBarOutlineFill, FVectorImageList);
 end;
 
 { TForm1 }
@@ -390,6 +403,15 @@ begin
   BackFillControl.OnAdjustToShape:= @RequestBackFillAdjustToShape;
   BackFillControl.OnResize:= @BackFillControlResize;
 
+  OutlineFillControl.ToolIconSize:= ActionIconSize;
+  OutlineFillControl.SolidColor := CSSYellow;
+  OutlineFillControl.FillType:= vftNone;
+  OutlineFillControl.GradStartColor := BGRAWhite;
+  OutlineFillControl.GradEndColor := CSSYellow;
+  OutlineFillControl.OnFillChange:= @RequestOutlineFillUpdate;
+  OutlineFillControl.OnAdjustToShape:= @RequestOutlineFillAdjustToShape;
+  OutlineFillControl.OnResize:= @OutlineFillControlResize;
+
   FSplineStyleMenu := TPopupMenu.Create(nil);
   for ss := low(TSplineStyle) to high(TSplineStyle) do
   begin
@@ -424,6 +446,7 @@ begin
   UpdateTitleBar;
   UpdateBackToolFillPoints;
   UpdatePenToolFillPoints;
+  UpdateOutlineToolFillPoints;
   UpdateShapeActions(nil);
 end;
 
@@ -636,6 +659,11 @@ begin
   PanelBackFill.ClientWidth := PanelBackFillHead.Width+BackFillControl.Width+2;
 end;
 
+procedure TForm1.OutlineFillControlResize(Sender: TObject);
+begin
+  PanelOutlineFill.ClientWidth := PanelOutlineFillHead.Width+OutlineFillControl.Width+2;
+end;
+
 procedure TForm1.PanelFileResize(Sender: TObject);
 begin
   ToolBarFile.Width := GetToolbarSize(ToolBarFile).cx;
@@ -727,6 +755,12 @@ begin
       newShape.PenFill := vectorFill;
       vectorFill.Free;
     end;
+    if (vsfOutlineFill in newShape.Fields) and (newShape.OutlineFill.FillType in [vftGradient, vftTexture]) then
+    begin
+      vectorFill := OutlineFillControl.CreateShapeFill(newShape);
+      newShape.OutlineFill := vectorFill;
+      vectorFill.Free;
+    end;
     rF := newShape.GetRenderBounds(InfiniteRect, vectorTransform);
     ImageChange(rF.Union(prevRF, true));
   end;
@@ -895,17 +929,27 @@ begin
     begin
       ToolButtonMove.Down := true;
       ButtonMovePenFillPoints.Down := false;
+      ButtonMoveOutlineFillPoints.Down := false;
     end;
   if Sender = ButtonMovePenFillPoints then
     if ButtonMovePenFillPoints.Down then
     begin
       ToolButtonMove.Down := true;
       ButtonMoveBackFillPoints.Down := false;
+      ButtonMoveOutlineFillPoints.Down := false;
+    end;
+  if Sender = ButtonMoveOutlineFillPoints then
+    if ButtonMoveOutlineFillPoints.Down then
+    begin
+      ToolButtonMove.Down := true;
+      ButtonMovePenFillPoints.Down := false;
+      ButtonMoveBackFillPoints.Down := false;
     end;
 
   FCurrentTool := ptHand;
   if ButtonMoveBackFillPoints.Down then FCurrentTool:= ptMoveBackFillPoint;
   if ButtonMovePenFillPoints.Down then FCurrentTool:= ptMovePenFillPoint;
+  if ButtonMoveOutlineFillPoints.Down then FCurrentTool:= ptMoveOutlineFillPoint;
   if ToolButtonEllipse.Down then FCurrentTool:= ptEllipse;
   if ToolButtonRectangle.Down then FCurrentTool:= ptRectangle;
   if ToolButtonPolyline.Down then FCurrentTool:= ptPolyline;
@@ -917,6 +961,7 @@ begin
 
   if currentTool <> ptMoveBackFillPoint then ButtonMoveBackFillPoints.Down := false;
   if currentTool <> ptMovePenFillPoint then ButtonMovePenFillPoints.Down := false;
+  if currentTool <> ptMoveOutlineFillPoint then ButtonMoveOutlineFillPoints.Down := false;
 
   if IsCreateShapeTool(currentTool) then
   begin
@@ -1074,6 +1119,7 @@ begin
   case currentTool of
     ptMoveBackFillPoint: if AShape.Usermode <> vsuEditBackFill then currentTool := ptHand;
     ptMovePenFillPoint: if AShape.Usermode <> vsuEditPenFill then currentTool := ptHand;
+    ptMoveOutlineFillPoint: if AShape.Usermode <> vsuEditOutlineFill then currentTool := ptHand;
   end;
   UpdateShapeActions(AShape);
   RemoveShapeIfEmpty(APreviousShape);
@@ -1119,6 +1165,15 @@ begin
   end;
 end;
 
+procedure TForm1.RequestOutlineFillUpdate(Sender: TObject);
+begin
+  if not FUpdatingFromShape then
+  begin
+    UpdateShapeOutlineFill;
+    UpdateOutlineToolFillPoints;
+  end;
+end;
+
 procedure TForm1.OnBackFillChange(ASender: TObject);
 begin
   if not FUpdatingFromShape then
@@ -1138,6 +1193,7 @@ begin
   ToolButtonPhongShape.Down:= FCurrentTool = ptPhongShape;
   ButtonMoveBackFillPoints.Down := FCurrentTool = ptMoveBackFillPoint;
   ButtonMovePenFillPoints.Down := FCurrentTool = ptMovePenFillPoint;
+  ButtonMoveOutlineFillPoints.Down := FCurrentTool = ptMoveOutlineFillPoint;
   UpdateShapeUserMode;
 end;
 
@@ -1466,6 +1522,7 @@ begin
     if vsfJoinStyle in f then joinStyle:= AShape.JoinStyle;
 
     if vsfBackFill in f then BackFillControl.AssignFill(AShape.BackFill);
+    if vsfOutlineFill in f then OutlineFillControl.AssignFill(AShape.OutlineFill);
 
     if AShape is TCurveShape then
       splineStyle:= TCurveShape(AShape).SplineStyle;
@@ -1489,6 +1546,7 @@ begin
     FUpdatingFromShape := false;
     PanelPenFill.Visible := vsfPenFill in f;
     PanelBackFill.Visible := vsfBackFill in f;
+    PanelOutlineFill.Visible := vsfOutlineFill in f;
   end else
   begin
     toolClass:= PaintToolClass[currentTool];
@@ -1498,16 +1556,19 @@ begin
       f := PaintToolClass[currentTool].Fields;
       PanelPenFill.Visible := vsfPenFill in f;
       PanelBackFill.Visible := vsfBackFill in f;
+      PanelOutlineFill.Visible := vsfOutlineFill in f;
     end
     else
     begin
       f := [];
       PanelPenFill.Visible := true;
       PanelBackFill.Visible := true;
+      PanelOutlineFill.Visible := true;
     end;
   end;
   UpdateBackToolFillPoints;
   UpdatePenToolFillPoints;
+  UpdateOutlineToolFillPoints;
   UpDownPenWidth.Enabled := vsfPenWidth in f;
   ButtonPenStyle.Enabled:= vsfPenStyle in f;
   EnableDisableToolButtons([ToolButtonJoinRound,ToolButtonJoinBevel,ToolButtonJoinMiter], vsfJoinStyle in f);
@@ -1656,6 +1717,7 @@ begin
   result := PaintToolClass[currentTool].Create(vectorOriginal);
   if (result is TCustomPolypointShape) and (BackFillControl.FillType = vftGradient) then BackFillControl.FillType := vftSolid;
   if (result is TCustomPolypointShape) and (PenFillControl.FillType = vftGradient) then PenFillControl.FillType := vftSolid;
+  if (result is TCustomPolypointShape) and (OutlineFillControl.FillType = vftGradient) then OutlineFillControl.FillType := vftSolid;
   result.PenWidth := penWidth;
   result.PenStyle := penStyle;
   if vsfJoinStyle in result.Fields then result.JoinStyle := joinStyle;
@@ -1692,6 +1754,12 @@ begin
     result.PenFill := vectorFill;
     vectorFill.Free;
   end;
+  if vsfOutlineFill in result.Fields then
+  begin
+    vectorFill := OutlineFillControl.CreateShapeFill(result);
+    result.OutlineFill := vectorFill;
+    vectorFill.Free;
+  end;
 end;
 
 procedure TForm1.RemoveExtendedStyleControls;
@@ -1740,18 +1808,35 @@ begin
   if (currentTool = ptMovePenFillPoint) and not canEdit then currentTool:= ptHand;
 end;
 
+procedure TForm1.UpdateOutlineToolFillPoints;
+var
+  canEdit: Boolean;
+begin
+  canEdit := (OutlineFillControl.FillType in[vftGradient,vftTexture]) and
+    Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape);
+  ButtonMoveOutlineFillPoints.Enabled := canEdit;
+  if (currentTool = ptMoveOutlineFillPoint) 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, True);
+    BackFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, ftBack);
 end;
 
 procedure TForm1.UpdateShapePenFill;
 begin
   if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
     (vsfPenFill in vectorOriginal.SelectedShape.Fields) then
-    PenFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, FAlse);
+    PenFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, ftPen);
+end;
+
+procedure TForm1.UpdateShapeOutlineFill;
+begin
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
+    (vsfOutlineFill in vectorOriginal.SelectedShape.Fields) then
+    OutlineFillControl.UpdateShapeFill(vectorOriginal.SelectedShape, ftOutline);
 end;
 
 procedure TForm1.UpdateShapeUserMode;
@@ -1772,8 +1857,15 @@ begin
       if vectorOriginal.SelectedShape.Usermode <> vsuEditPenFill then
         vectorOriginal.SelectedShape.Usermode := vsuEditPenFill;
     end else
+    if (currentTool = ptMoveOutlineFillPoint) and
+       (vsfOutlineFill in vectorOriginal.SelectedShape.Fields) and
+       vectorOriginal.SelectedShape.OutlineFill.IsEditable then
+    begin
+      if vectorOriginal.SelectedShape.Usermode <> vsuEditOutlineFill then
+        vectorOriginal.SelectedShape.Usermode := vsuEditOutlineFill;
+    end else
     begin
-      if vectorOriginal.SelectedShape.Usermode in[vsuEditPenFill,vsuEditBackFill] then
+      if vectorOriginal.SelectedShape.Usermode in[vsuEditPenFill,vsuEditBackFill,vsuEditOutlineFill] then
         vectorOriginal.SelectedShape.Usermode := vsuEdit;
     end;
   end;
@@ -1790,6 +1882,7 @@ begin
   EditDelete.Enabled := AShape <> nil;
   BackFillControl.CanAdjustToShape := AShape <> nil;
   PenFillControl.CanAdjustToShape := AShape <> nil;
+  OutlineFillControl.CanAdjustToShape := AShape <> nil;
 end;
 
 procedure TForm1.RemoveShapeIfEmpty(AShape: TVectorShape);
@@ -1849,7 +1942,8 @@ procedure TForm1.RequestBackFillAdjustToShape(Sender: TObject);
 var
   vectorFill: TVectorialFill;
 begin
-  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) then
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
+     (vsfBackFill in vectorOriginal.SelectedShape.Fields) then
   begin
     vectorFill := BackFillControl.CreateShapeFill(vectorOriginal.SelectedShape);
     vectorOriginal.SelectedShape.BackFill := vectorFill;
@@ -1866,7 +1960,8 @@ procedure TForm1.RequestPenFillAdjustToShape(Sender: TObject);
 var
   vectorFill: TVectorialFill;
 begin
-  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) then
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
+     (vsfPenFill in vectorOriginal.SelectedShape.Fields) then
   begin
     vectorFill := PenFillControl.CreateShapeFill(vectorOriginal.SelectedShape);
     vectorOriginal.SelectedShape.PenFill := vectorFill;
@@ -1883,6 +1978,19 @@ begin
   end;
 end;
 
+procedure TForm1.RequestOutlineFillAdjustToShape(Sender: TObject);
+var
+  vectorFill: TVectorialFill;
+begin
+  if Assigned(vectorOriginal) and Assigned(vectorOriginal.SelectedShape) and
+     (vsfOutlineFill in vectorOriginal.SelectedShape.Fields) then
+  begin
+    vectorFill := OutlineFillControl.CreateShapeFill(vectorOriginal.SelectedShape);
+    vectorOriginal.SelectedShape.OutlineFill := vectorFill;
+    vectorFill.Free;
+  end;
+end;
+
 procedure TForm1.AdjustToolbarTop;
 begin
   ReorderToolbarContent(ToolbarTop);