// SPDX-License-Identifier: LGPL-3.0-linking-exception
{ A Graphic Button Control that uses SVG images as the button states
  for Normal,Hover and DOWN states.

  originally written in 2018 by User Josh on Lazarus Forum.

  You can use the SVGDOWNXML property to enter the SVG XML code to create the
  image or You can enter the full svg image file and pathname into the properties
  FileNameDown; it will then read in the File Information and place it in the
  SVGDownXML Property.

  This Component uses the BGRABITMAP and BGRACONTROLS Framework to implement
  the Button's Functionality
}
{******************************* CONTRIBUTOR(S) ******************************
- Edivando S. Santos Brasil | mailedivando@gmail.com
  (Compatibility with delphi VCL 11/2018)

***************************** END CONTRIBUTOR(S) *****************************}
unit BCSVGButton;

{$I bgracontrols.inc}

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
  {$IFDEF FPC}LResources, lazutils,{$ENDIF}
  {$IFNDEF FPC}Windows, Messages, BGRAGraphics, GraphType, FPImage, {$ENDIF}
  BCSVGViewer;

type

  SVGButtonState = (MouseIn, MouseOut, Pressed);

  TBCSVGButton = class(TBCSVGViewer)
  private
    fsvgnormal:tstrings;
    fsvghover:tstrings;
    fsvgdown:tstrings;
    fdown:boolean;
    FState:SVGButtonState;
    FOwner: TComponent;
    FFileNameHover: String;
    FFileNameNormal: String;
    FFileNameDown: String;
    FPosition: Integer;
    FMax: Integer;
    FInfo1: String;
    FInfo2: String;
  //  property OnPositionChange;
    procedure setdown(AValue: boolean);
    procedure ReadSVGFileAndSetString(fn:String;itm:Integer);
    procedure GenerateCompletedSVGImage(AValue: string);
  protected
    FOnPositionChange: TNotifyEvent;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      MX, MY: integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; MX, MY: integer); override;
    procedure MouseEnter; override;
    procedure MouseLeave; override;
    procedure setsvghoverxml(const AValue: tstrings);
    procedure setsvgnormalxml(const AValue: tstrings);
    procedure setsvgdownxml(const AValue: tstrings);
    procedure setFFileNameDown(const AValue: string);
    procedure setFFileNameHover(const AValue: string);
    procedure setFFileNameNormal(const AValue: string);
    procedure SetInfo1(const AValue:String);
    procedure SetInfo2(const AValue:String);
    procedure Setposition(const AValue:Integer);
    procedure SetMax(const AValue:Integer);
    procedure RedrawBitmapContent; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure paint; override;
  published
    property BorderSpacing;
    property Constraints;
    Property FileNameDown : String Read FFileNameDown Write setFFileNameDown;
    Property FileNameHover : String Read FFileNameHover Write setFFileNameHover;
    Property FileNameNormal : String Read FFileNameNormal Write setFFileNameNormal;
    property SVGNormalXML:tstrings read fsvgnormal write setsvgnormalxml;
    property SVGHoverXML:tstrings read fsvghover write setsvghoverxml;
    property SVGDownXML:tstrings read fsvgdown write setsvgdownxml;
    property Down:boolean read fdown write setdown default false;
    property Information1:string read FInfo1 write SetInfo1;
    property Information2:string read FInfo2 write SetInfo2;
    property Position:integer read fposition write SetPosition;
    property Maximum:integer read fmax write SetMax;
    property OnPositionChange: TNotifyEvent read FOnPositionChange write FOnPositionChange;
  end;

{$IFDEF FPC}procedure Register;{$ENDIF}

implementation

procedure TBCSVGButton.Paint;
begin
  inherited Paint;
end;

constructor TBCSVGButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FOwner := AOwner;
  fsvgnormal :=  TStringList.Create;
  fsvghover :=  TStringList.Create;
  fsvgdown :=  TStringList.Create;
  FState := MouseOut;
end;

destructor TBCSVGButton.Destroy;
begin
  fsvghover.Free;
  fsvghover := nil;
  fsvgnormal.Free;
  fsvgnormal := nil;
  fsvgdown.Free;
  fsvgdown := nil;
  inherited Destroy;
end;

//FSVG.CreateFromString(fsvgnormal.Text);
procedure TBCSVGButton.GenerateCompletedSVGImage(AValue: string);
begin
  FSVG.CreateFromString(AValue);
end;

procedure TBCSVGButton.ReadSVGFileAndSetString(fn:String;itm:Integer);
var li,st: {$IFDEF FPC}ansistring{$ELSE}string{$ENDIF};
    F: {$IFDEF FPC}Text{$ELSE}TextFile{$ENDIF};

begin
  li:='';
  st:='';
  if  fileexists(fn) then
  begin
    AssignFile(F,fn);
    {$I-}
    Reset(F);
    {$I+}
    If (IoResult = 0) Then
    Begin
      While Not(EoF(F)) Do
      Begin
        ReadLn(F,Li);
        st:=st+li;
        If (EoF(F)) Then Break;
      End;
    End;
    CloseFile(F);
  end else showmessage('File Not Found');
  case itm of
    0:begin
        if st<>'' then fsvgNormal.Text:=st;
        FFileNameNormal:='';
      end;
    1:Begin
        if st<>'' then fsvgHover.Text:=st;
        FFileNameHover:='';
      End;
    2:Begin
        if st<>'' then fsvgDown.Text:=st;
        FFileNameDown:='';
      ENd;
  end;
  if st<>'' then RedrawBitmap;
End;

procedure TBCSVGButton.SetInfo1(const AValue: string);
begin
  If AValue<>'' then FInfo1:=AValue;
end;

procedure TBCSVGButton.SetInfo2(const AValue: string);
begin
  If AValue<>'' then FInfo2:=AValue;
end;

procedure TBCSVGButton.setposition(const AValue: Integer);
begin
  If AValue<>FPosition then
  begin
    FPosition:=AValue;
    if assigned(FOnPositionChange) then FOnPositionChange(self);
  end;
end;

procedure TBCSVGButton.setmax(const AValue: Integer);
begin
  If AValue<>Fmax then Fmax:=AValue;
end;

procedure TBCSVGButton.setFFileNameNormal(const AValue: string);
begin
  If AValue<>'' then ReadSVGFileAndSetString(AValue,0);
end;

procedure TBCSVGButton.setFFileNameHover(const AValue: string);
begin
  If AValue<>'' then ReadSVGFileAndSetString(Avalue,1);
end;

procedure TBCSVGButton.setFFileNameDown(const AValue: string);
begin
  If AValue<>'' then ReadSVGFileAndSetString(Avalue,2);
End;

procedure TBCSVGButton.setsvgnormalxml(const AValue: tstrings);
begin
  if fsvgnormal.Text = AValue.Text then
    Exit;
  fsvgnormal.Assign(AValue);
  DiscardBitmap;
  if FDown=false then if fsvgnormal.Text<>'' then GenerateCompletedSVGImage(fsvgnormal.Text);
  RedrawBitmap;
 // if not fdown then RedrawBitmap;
end;

procedure TBCSVGButton.setsvghoverxml(const AValue: tstrings);
begin
  if fsvghover.Text = AValue.Text then
    Exit;
  fsvghover.Assign(AValue);
  DiscardBitmap;
end;

procedure TBCSVGButton.setsvgdownxml(const AValue: tstrings);
begin
  if fsvgdown.Text = AValue.Text then
    Exit;
  fsvgdown.Assign(AValue);
  DiscardBitmap;
  if FDown then
  begin
    if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text);
    RedrawBitmap;
  end;
end;

procedure TBCSVGButton.setdown(AValue: boolean);
begin
  if fdown = AValue then
    Exit;
  fdown := AValue;
  if fdown=false then Fstate:=MouseOut;
  DiscardBitmap;
  if FDown then
  begin
    if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text);
  end
  else
  begin
    if fsvgnormal.Text<>'' then GenerateCompletedSVGImage(fsvgnormal.Text);
  end;
  RedrawBitmap;
end;

procedure TBCSVGButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  MX, MY: integer);
begin
  inherited MouseDown(Button, Shift, MX, MY);
  if csDesigning in ComponentState then
    exit;

  if (Button = mbLeft) and Enabled then
  begin
    FState := Pressed;
    if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text);
//    RedrawBitmapContent;
    RedrawBitmap;
  end;
end;

procedure TBCSVGButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  MX, MY: integer);
begin
  inherited MouseUp(Button, Shift, MX, MY);

  if csDesigning in ComponentState then exit;

  if (Button = mbLeft) and Enabled then
  begin
    if FDown then
    begin
      if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text)
    end
    else
    begin
      if fsvghover.Text<>'' then GenerateCompletedSVGImage(fsvghover.Text);
    end;
    FState := MouseIn;
 //   RedrawBitmapContent;
    RedrawBitmap;
  end;
end;

procedure TBCSVGButton.MouseEnter;
begin
  if csDesigning in ComponentState then exit;

  inherited MouseEnter;

  if fsvghover.Text<>'' then GenerateCompletedSVGImage(fsvghover.Text);
  FState := MouseIn;
 // RedrawBitmapContent;
  RedrawBitmap;

end;

procedure TBCSVGButton.MouseLeave;
begin
  inherited MouseLeave;
  if csDesigning in ComponentState then
    exit;
  if FDown then
  begin
    if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text)
  end
  else
  begin
    if fsvgnormal.Text<>'' then GenerateCompletedSVGImage(fsvgnormal.Text);
  end;
  FState := MouseOut;
//  RedrawBitmapContent;
  RedrawBitmap;

end;

procedure TBCSVGButton.RedrawBitmapContent;
begin
  if FDown then
  begin
    if fsvgdown.Text<>'' then GenerateCompletedSVGImage(fsvgdown.Text)
  end
  else
  begin
    case fstate of
      mousein :if fsvghover.Text<>'' then GenerateCompletedSVGImage(fsvghover.Text);
      mouseout:if fsvgnormal.Text<>'' then GenerateCompletedSVGImage(fsvgnormal.Text);
    end;
  end;
  inherited RedrawBitmapContent;
end;

{$IFDEF FPC}
procedure Register;
begin
  {$I icons\bcsvgbutton.lrs}
  RegisterComponents('BGRA Button Controls',[TBCSVGButton]);
end;
{$ENDIF}



end.
