unit SVGCustomGaugeMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Types, UITypes,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, RSGdiPlusCtrls, RSGdiPlusGraphicsTypes,
  RSSVG, RSSVGTypes, RSGraphics, RSSVGCtrls, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TfrmSpeedometer = class(TForm)
    RSSVGDocument1: TRSSVGDocument;
    Label1: TLabel;
    ColorBox1: TColorBox;
    Panel1: TPanel;
    TrackBar1: TTrackBar;
    RSSVGScreen1: TRSSVGScreen;
    ColorBox2: TColorBox;
    ColorBox3: TColorBox;
    ColorBox4: TColorBox;
    ColorBox5: TColorBox;
    CheckBox1: TCheckBox;
    CheckBox2: TCheckBox;
    CheckBox3: TCheckBox;
    CheckBox4: TCheckBox;
    CheckBox5: TCheckBox;
    CheckBox6: TCheckBox;
    procedure TrackBar1Change(Sender: TObject);
    procedure ColorBox1Change(Sender: TObject);
    procedure ColorBox2Change(Sender: TObject);
    procedure ColorBox3Change(Sender: TObject);
    procedure ColorBox4Change(Sender: TObject);
    procedure ColorBox5Change(Sender: TObject);
    procedure CheckBox1Click(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
    procedure CheckBox3Click(Sender: TObject);
    procedure CheckBox5Click(Sender: TObject);
    procedure CheckBox6Click(Sender: TObject);
    procedure CheckBox4Click(Sender: TObject);
  private
    { Private declarations }
    FTaggedMarkers: Boolean;
  public
    { Public declarations }
    procedure TagMarkersAndText;
  end;

var
  frmSpeedometer: TfrmSpeedometer;

implementation

{$R *.dfm}
uses
  Math;

procedure TfrmSpeedometer.CheckBox1Click(Sender: TObject);
begin
  (RSSVGDocument1.SVG.AllItems['glassShine'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
end;

procedure TfrmSpeedometer.CheckBox2Click(Sender: TObject);
begin
  (RSSVGDocument1.SVG.AllItems['NeedleGroup'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
end;

procedure TfrmSpeedometer.CheckBox3Click(Sender: TObject);
begin
  RSSVGDocument1.SVG.BeginUpdate;
  try
    (RSSVGDocument1.SVG.AllItems['speed40'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['speed80'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['speed120'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['speed160'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['speed200'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.CheckBox4Click(Sender: TObject);
begin
  (RSSVGDocument1.SVG.AllItems['markers'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
end;

procedure TfrmSpeedometer.CheckBox5Click(Sender: TObject);
begin
  RSSVGDocument1.SVG.BeginUpdate;
  try
    (RSSVGDocument1.SVG.AllItems['backface'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['backfaceHighlight'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.CheckBox6Click(Sender: TObject);
begin
  RSSVGDocument1.SVG.BeginUpdate;
  try
    (RSSVGDocument1.SVG.AllItems['innerFrame'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
    (RSSVGDocument1.SVG.AllItems['outerFrame'] as TSVGGraphicElement).Visible := (Sender as TCheckBox).Checked;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.ColorBox1Change(Sender: TObject);
var
  Shine: TSVGLinearGradient;
  i: Integer;
  NewColor: TSVGColorRec;
begin
  NewColor := (Sender as TColorBox).Selected;
  RSSVGDocument1.SVG.BeginUpdate;
  try
    // find linear gradient for glass shine
    Shine := RSSVGDocument1.SVG.AllItems['linearGradientShine'] as TSVGLinearGradient;
    // set gradient stops' colors to new color
    for i := 0 to Shine.Items.Count - 1 do
    begin
      // reduce opacity because it looks better
      if (Shine.Items[i] as TSVGGradientStop).StopBrush.Opacity > 0 then
        (Shine.Items[i] as TSVGGradientStop).StopBrush.Opacity := 0.5;
      (Shine.Items[i] as TSVGGradientStop).StopBrush.Color := NewColor;
    end;
    // rebuild all brushes so that they ask for new gradients
    RSSVGDocument1.SVG.Reset;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.ColorBox2Change(Sender: TObject);
var
  Needle: TSVGGraphicElement;
  NewColor: TSVGColorRec;
begin
  NewColor := (Sender as TColorBox).Selected;
  RSSVGDocument1.SVG.BeginUpdate;
  try
    // get needle
    Needle := RSSVGDocument1.SVG.AllItems['Needle'] as TSVGGraphicElement;
    // change its color
    Needle.Brush.Color := NewColor;
    // dim colors
    NewColor.R := trunc(NewColor.R * 0.5);
    NewColor.G := trunc(NewColor.G * 0.5);
    NewColor.B := trunc(NewColor.B * 0.5);
    // get highlight
    Needle := RSSVGDocument1.SVG.AllItems['NeedleHighlight'] as TSVGGraphicElement;
    // change its color
    Needle.Brush.Color := NewColor;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.ColorBox3Change(Sender: TObject);
var
  NewColor: TSVGColorRec;
  aElement: TSVGElement;
begin
  NewColor := (Sender as TColorBox).Selected;
  RSSVGDocument1.SVG.BeginUpdate;
  try
    if not FTaggedMarkers then
      TagMarkersAndText;
    // go through all elements and change tagged ones to the new color
    for aElement in RSSVGDocument1.SVG.AllItems.Values do
      if aElement.Tag = 1 then
      begin
        TSVGGraphicElement(aElement).Inherits.Fill := False;
        TSVGGraphicElement(aElement).Brush.Color := NewColor;
      end;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.ColorBox4Change(Sender: TObject);
var
  Backface: TSVGLinearGradient;
  NewColor: TSVGColorRec;
  i: Integer;
begin
  NewColor := (Sender as TColorBox).Selected;
  RSSVGDocument1.SVG.BeginUpdate;
  try
    // get Backface gradient highlight
    Backface := RSSVGDocument1.SVG.AllItems['linearGradientBackfaceHighlight'] as TSVGLinearGradient;
    for i := 0 to Backface.Items.Count - 1 do
      (Backface.Items[i] as TSVGGradientStop).StopBrush.Color := NewColor;
    // get Backface gradient
    Backface := RSSVGDocument1.SVG.AllItems['linearGradientBackface'] as TSVGLinearGradient;
    (Backface.Items[0] as TSVGGradientStop).StopBrush.Color := NewColor;
    // dim colors
    NewColor.R := trunc(NewColor.R * 0.5);
    NewColor.G := trunc(NewColor.G * 0.5);
    NewColor.B := trunc(NewColor.B * 0.5);
    (Backface.Items[1] as TSVGGradientStop).StopBrush.Color := NewColor;
    // rebuild all brushes so that they ask for new gradients
    RSSVGDocument1.SVG.Reset;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.ColorBox5Change(Sender: TObject);
var
  Frame: TSVGGraphicElement;
  FrameGradient: TSVGLinearGradient;
  NewColor: TSVGColorRec;
begin
  NewColor := (Sender as TColorBox).Selected;
  RSSVGDocument1.SVG.BeginUpdate;
  try
    // get Frame gradient
    FrameGradient := RSSVGDocument1.SVG.AllItems['linearGradientFrame'] as TSVGLinearGradient;
    (FrameGradient.Items[0] as TSVGGradientStop).StopBrush.Color := NewColor;
    // dim colors
    NewColor.R := trunc(NewColor.R * 0.3);
    NewColor.G := trunc(NewColor.G * 0.3);
    NewColor.B := trunc(NewColor.B * 0.3);
    (FrameGradient.Items[1] as TSVGGradientStop).StopBrush.Color := NewColor;
    // get Frame
    Frame := RSSVGDocument1.SVG.AllItems['innerFrame'] as TSVGGraphicElement;
    Frame.Brush.Color := NewColor;
    // rebuild all brushes so that they ask for new gradients
    RSSVGDocument1.SVG.Reset;
  finally
    RSSVGDocument1.SVG.EndUpdate;
  end;
end;

procedure TfrmSpeedometer.TagMarkersAndText;
var
  aElement: TSVGElement;
begin
  for aElement in RSSVGDocument1.SVG.AllItems.Values do
    if (aElement is TSVGGraphicElement) and
       (TSVGGraphicElement(aElement).Brush.Color = TSVGColorRec.White) and
       (aElement.ID <> 'Needle') then
      aElement.Tag := 1;
  FTaggedMarkers := True;
end;

procedure TfrmSpeedometer.TrackBar1Change(Sender: TObject);
const
  LowGauge = -109;
  HiGauge = 187+LowGauge;
var
  Needle: TSVGGraphicElement;
  NeedleAngle: Single;
  aRect: TSVGRect;
begin
  Label1.Caption := TTrackBar(Sender).Position.ToString;
  // Get Needle Group to manipulate
  Needle := RSSVGDocument1.SVG.AllItems['NeedleGroup'] as TSVGGraphicElement;
  aRect := Needle.BoundsRect;
  // scale trackbar value into between Min and Max
  NeedleAngle := TTrackBar(Sender).Position;
  NeedleAngle := ((NeedleAngle-TTrackBar(Sender).Min)/(TTrackBar(Sender).Max-TTrackBar(Sender).Min))*(HiGauge-LowGauge)+LowGauge;
  // rotate around bottom left
  Needle.Matrix := CreateRotationRSMatrix(RSPoint(aRect.Left, aRect.Bottom), DegToRad(NeedleAngle));
end;

end.
