Gauge in Firemonkey - Delphi-PRAXiS (2024)

unit UGauge;

interface

uses System.Types, System.Classes, System.UITypes,
FMX.Types, FMX.Graphics, FMX.Controls;

type
TGauge = class(TControl)
protected
FFlatMode: Boolean;
FBackColor: TAlphaColor;
FDialColor: TAlphaColor;
FForeColor: TAlphaColor;

FGlossAlpha: Byte;

FCurrentValue: Single;
FThreshHold: Single;
FCaptureThresh: Boolean;
FMaxValue: Single;
FMinValue: Single;

FToAngle: Single;
FFromAngle: Single;

FNoOfDivisions: integer;
FNoOfSubDivisions: integer;

FGaugeName: String;

procedure DrawDigit(const Canvas: TCanvas; const number: integer;
const position: TPointF; const dp: Boolean; const height: Single);

procedure DisplayNumber(const Canvas: TCanvas;
const X, Y, Width, height: Single; const number: Single);
procedure DrawBackground(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
procedure DrawCenterPoint(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
procedure DrawCallibration(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
procedure DrawPointer(const Canvas: TCanvas; const Width: Single;
const Center: TPointF; const Thresh: Boolean = false);
procedure DrawGloss(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);

procedure SetCurrentValue(const Value: Single);
procedure Paint; override;
procedure SetFlatMode(const Value: Boolean);
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;

procedure ResetThreshold;

property BackColor: TAlphaColor read FBackColor write FBackColor;
property ForeColor: TAlphaColor read FForeColor write FForeColor;
property DialColor: TAlphaColor read FDialColor write FDialColor;
property GlossAlpha: Byte read FGlossAlpha write FGlossAlpha;
property CurrentValue: Single read FCurrentValue write SetCurrentValue;
property MaxValue: Single read FMaxValue write FMaxValue;
property MinValue: Single read FMinValue write FMinValue;
property ToAngle: Single read FToAngle write FToAngle;
property FromAngle: Single read FFromAngle write FFromAngle;
property noOfDivisions: integer read FNoOfDivisions write FNoOfDivisions;
property noOfSubDivisions: integer read FNoOfSubDivisions
write FNoOfSubDivisions;
property GaugeName: String read FGaugeName write FGaugeName;
property CaptureThresh: Boolean read FCaptureThresh write FCaptureThresh;
property FlatMode: Boolean read FFlatMode write SetFlatMode default false;
published
property Align;
property Anchors;
property ClipChildren default false;
property ClipParent default false;
property DesignVisible default True;
property Enabled default True;
property Locked default false;
property height;
property HitTest default True;
property Padding;
property Opacity;
property Margins;
property PopupMenu;
property position;
property RotationAngle;
property RotationCenter;
property Scale;
property Visible default True;
property Width;
{ Mouse events }
property OnClick;
property OnDblClick;

property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseEnter;
property OnMouseLeave;

property OnPainting;
property OnPaint;
property OnResize;
end;

implementation

uses System.SysUtils, System.Character, FMX.Platform;

{ TGauge }
constructor TGauge.Create{$IFDEF COMPONENT}(AOwner: TComponent){$ENDIF};
begin
inherited;
{$IFDEF ANDROID}
FFlatMode := True;
{$ENDIF}
FBackColor := $FF000080;
FDialColor := $FFE6E6FA;
FForeColor := $FF000000;

MaxValue := 100;
MinValue := 0;
CurrentValue := 0;

FromAngle := 135;
ToAngle := 405;

noOfDivisions := 10;
noOfSubDivisions := 3;
FGaugeName := '';

GlossAlpha := 200;
end;

destructor TGauge.Destroy;
begin
inherited;
end;

procedure TGauge.DrawCallibration(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
var
currentAngle: Single;
gap: integer;
X, Y, x1, y1, tx, ty, radius: Single;
rulerValue, incr, totalAngle: Single;
i, j: integer;
begin
gap := trunc(Width * 0.01);
radius := Width / 2 - gap * 5;

currentAngle := FromAngle * PI / 180;
totalAngle := ToAngle - FromAngle;

incr := totalAngle / (noOfDivisions * noOfSubDivisions) * PI / 180;
rulerValue := MinValue;

Canvas.stroke.Kind := TBrushKind.bkSolid;
Canvas.stroke.Color := $FF000000;

Canvas.Fill.Color := $FF000000 or (FForeColor and $FFFFFF);
Canvas.Font.Size := Width / 24;

for i := 0 to noOfDivisions do
begin
// Draw Thick Line
X := (Center.X + radius * Cos(currentAngle));
Y := (Center.Y + radius * Sin(currentAngle));
x1 := (Center.X + (radius - Width / 20) * Cos(currentAngle));
y1 := (Center.Y + (radius - Width / 20) * Sin(currentAngle));
Canvas.DrawLine(PointF(X, Y), PointF(x1, y1), 1);

// Draw Strings
tx := (Center.X + (radius - Width / 10) * Cos(currentAngle));
ty := (Center.Y - Width / 25 + (radius - Width / 10) * Sin(currentAngle));

Canvas.FillText(RectF(tx, ty, tx + 1024, ty + 1024), floattostr(rulerValue),
false, 1, [], TTextAlign.taLeading, TTextAlign.taLeading);

rulerValue := rulerValue + round((MaxValue - MinValue) / noOfDivisions);

if i < noOfDivisions then
for j := 0 to noOfSubDivisions - 1 do
begin
// Draw thin lines
currentAngle := currentAngle + incr;
X := (Center.X + radius * Cos(currentAngle));
Y := (Center.Y + radius * Sin(currentAngle));
x1 := (Center.X + (radius - Width / 50) * Cos(currentAngle));
y1 := (Center.Y + (radius - Width / 50) * Sin(currentAngle));
Canvas.DrawLine(PointF(X, Y), PointF(x1, y1), 1);
end;
end;
end;

procedure TGauge.DrawPointer(const Canvas: TCanvas; const Width: Single;
const Center: TPointF; const Thresh: Boolean = false);
var
radius: Single;
val: Single;
angle: Single;
pts: TPolygon;
Value, w, len: Single;

begin
radius := Width / 2 - (Width * 0.12);
val := MaxValue - MinValue;

if Thresh then
begin
w := 6;
Value := FThreshHold;
len := 0.09;
end
else
begin
w := 20;
Value := CurrentValue;
len := 0.09;
end;

val := (100 * (Value - MinValue)) / val;
val := ((ToAngle - FromAngle) * val) / 100;
val := val + FromAngle;

angle := val * PI / 180;

setlength(pts, 5);
pts[0].X := (Center.X + radius * Cos(angle));
pts[0].Y := (Center.Y + radius * Sin(angle));

pts[4].X := (Center.X + radius * Cos(angle - 0.02));
pts[4].Y := (Center.Y + radius * Sin(angle - 0.02));

angle := (val + w) * PI / 180;
pts[1].X := (Center.X + (Width * len) * Cos(angle));
pts[1].Y := (Center.Y + (Width * len) * Sin(angle));

pts[2].X := Center.X;
pts[2].Y := Center.Y;

angle := (val - w) * PI / 180;
pts[3].X := (Center.X + (Width * len) * Cos(angle));
pts[3].Y := (Center.Y + (Width * len) * Sin(angle));

if Thresh then
Canvas.Fill.Color := $FFFF0000
else
Canvas.Fill.Color := $FF000000;
Canvas.FillPolygon(pts, 1);

if Thresh then
exit;

setlength(pts, 3);
angle := val * PI / 180;
pts[0].X := (Center.X + radius * Cos(angle));
pts[0].Y := (Center.Y + radius * Sin(angle));

angle := (val + w) * PI / 180;
pts[1].X := (Center.X + (Width * len) * Cos(angle));
pts[1].Y := (Center.Y + (Width * len) * Sin(angle));

pts[2].X := Center.X;
pts[2].Y := Center.Y;

if FFlatMode then
begin
Canvas.Fill.Color := $FF808080;
Canvas.FillPolygon(pts, 2);
end
else
begin
Canvas.Fill.Kind := TBrushKind.bkGradient;
try
Canvas.Fill.Gradient.Color := $FF808080;
Canvas.Fill.Gradient.Color1 := $0F000000;
Canvas.FillPolygon(pts, 1);
finally
Canvas.Fill.Kind := TBrushKind.bkSolid;
end;
end;
end;

procedure TGauge.DrawGloss(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
var
R: TRectF;
X, Y: Single;
begin
R := RectF(Center.X - Width / 2, Center.Y - Width / 2, Center.X + Width / 2,
Center.Y + Width / 2);
if not FFlatMode then
Canvas.Fill.Kind := TBrushKind.bkGradient;

try
if not FFlatMode then
begin
Canvas.Fill.Gradient.Color := (GlossAlpha and $FF) shl 24 or $FFFFFF;
Canvas.Fill.Gradient.Color1 := $00FFFFFF;
end
else
Canvas.Fill.Color := $20303030;

X := R.Left + (Width * 0.10);
Y := R.Top + (Width * 0.07);
Canvas.FillEllipse(RectF(X, Y, X + (Width * 0.80), Y + (Width * 0.7)), 1);
Canvas.Fill.Color := ((GlossAlpha div 3) and $FF) shl 24 or
(FBackColor and $FFFFFF);

if not FFlatMode then
begin
Canvas.Fill.Gradient.Color := $00FFFFFF;
Canvas.Fill.Gradient.Color1 := Canvas.Fill.Color;
end;

X := R.Left + Width * 0.25;
Y := R.Top + Width * 0.77;
Canvas.FillEllipse(RectF(X, Y, X + Width * 0.5, Y + Width * 0.2), 1);
finally
Canvas.Fill.Kind := TBrushKind.bkSolid;
end;
end;

procedure TGauge.DrawCenterPoint(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
var
R: TRectF;
shift: Single;
begin
shift := Width / 5;
R := RectF(Center.X - (shift / 2), Center.Y - (shift / 2),
Center.X + (shift / 2), Center.Y + (shift / 2));

if not FFlatMode then
Canvas.Fill.Kind := TBrushKind.bkGradient;

try
Canvas.Fill.Color := 100 shl 24 or (FDialColor and $FFFFFF);
if not FFlatMode then
begin
Canvas.Fill.Gradient.Color := $FF000000;
Canvas.Fill.Gradient.Color1 := Canvas.Fill.Color;
end;
Canvas.FillEllipse(R, 1);

shift := Width / 7;
R := RectF(Center.X - (shift / 2), Center.Y - (shift / 2),
Center.X + (shift / 2), Center.Y + (shift / 2));

if FFlatMode then
Canvas.Fill.Color := $FF808080
else
begin
Canvas.Fill.Gradient.Color := $FF808080;
Canvas.Fill.Gradient.Color1 := $FF000000;
end;

Canvas.FillEllipse(R, 1);
finally
Canvas.Fill.Kind := TBrushKind.bkSolid;
end;
end;

procedure TGauge.DrawBackground(const Canvas: TCanvas; const Width: Single;
const Center: TPointF);
var
R: TRectF;
X, Y: Single;
begin
R := RectF(Center.X - (Width / 2), Center.Y - (Width / 2),
Center.X + (Width / 2), Center.Y + (Width / 2));
Canvas.Fill.Color := 120 shl 24 or (FDialColor and $FFFFFF);
Canvas.FillEllipse(R, 1);

// Draw Rim
Canvas.stroke.Kind := TBrushKind.bkSolid;
Canvas.stroke.Color := $64808080;
Canvas.DrawEllipse(R, 1);

Canvas.stroke.Color := $FF808080;
Canvas.DrawEllipse(R, 1);

Canvas.Fill.Color := $FF000000 or (FForeColor and $FFFFFF);
// Canvas.Font.Size := Width / 18;

Canvas.FillText(RectF(0, Center.Y + (Width / 4.5), Width, Height), FGaugeName, false, 1,
[], TTextAlign.taCenter, TTextAlign.taLeading);

DrawCallibration(Canvas, Width, Center);

X := Center.X - Width / 4.8;
Y := Center.Y + Width / 3.2;

DisplayNumber(Canvas, X, Y, Width, Width / 8, CurrentValue);
end;

procedure TGauge.DisplayNumber(const Canvas: TCanvas;
const X, Y, Width, height: Single; const number: Single);
var
num: string;
shift: Single;
drawDPS: Boolean;
c: char;
i: integer;
begin
num := formatfloat('000.0', number);

shift := 0;
if (number < 0) then
shift := shift - Width / 17;

for i := low(num) to high(num) do
begin
c := num[i];
drawDPS := (i < high(num)) and (num[i + 1].IsInArray([',', '.']));

if (c <> '.') and (c <> ',') then
begin
if (c = '-') then
DrawDigit(Canvas, -1, PointF(X + shift, Y), drawDPS, height)
else
DrawDigit(Canvas, StrToInt(c), PointF(X + shift, Y), drawDPS, height);
shift := shift + 24 * Width / 250;
end
else
shift := shift + 8 * Width / 250;
end;
end;

procedure TGauge.DrawDigit(const Canvas: TCanvas; const number: integer;
const position: TPointF; const dp: Boolean; const height: Single);
var
Width: Single;
outline, fillpen: Cardinal;
Segment: TPolygon;

function GetX(const X, Width: Single): Single; inline;
begin
result := X * Width / 12;
end;

function GetY(const Y, height: Single): Single; inline;
begin
result := Y * height / 15;
end;

function IsNumberAvailable(const number: integer;
const list: array of integer): Boolean;
var
i: integer;
begin
result := false;
for i := low(list) to high(list) do
if (number = list[i]) then
begin
result := True;
exit;
end;
end;

begin
Width := 10 * height / 13;

outline := 40 shl 24 or (FDialColor and $FFFFFF);
fillpen := $FF000000;

Canvas.Fill.Color := outline;

// Segment A
setlength(Segment, 5);
Segment[0] := PointF(position.X + GetX(2.8, Width),
position.Y + GetY(1, height));
Segment[1] := PointF(position.X + GetX(10, Width),
position.Y + GetY(1, height));
Segment[2] := PointF(position.X + GetX(8.8, Width),
position.Y + GetY(2, height));
Segment[3] := PointF(position.X + GetX(3.8, Width),
position.Y + GetY(2, height));
Segment[4] := Segment[0];

if (IsNumberAvailable(number, [0, 2, 3, 5, 6, 7, 8, 9])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;
Canvas.FillPolygon(Segment, 1);

// Segment B
Segment[0] := PointF(position.X + GetX(10, Width),
position.Y + GetY(1.4, height));
Segment[1] := PointF(position.X + GetX(9.3, Width),
position.Y + GetY(6.8, height));
Segment[2] := PointF(position.X + GetX(8.4, Width),
position.Y + GetY(6.4, height));
Segment[3] := PointF(position.X + GetX(9, Width),
position.Y + GetY(2.2, height));
Segment[4] := Segment[0];
if (IsNumberAvailable(number, [0, 1, 2, 3, 4, 7, 8, 9])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;
Canvas.FillPolygon(Segment, 1);

// Segment C
Segment[0] := PointF(position.X + GetX(9.2, Width),
position.Y + GetY(7.2, height));
Segment[1] := PointF(position.X + GetX(8.7, Width),
position.Y + GetY(12.7, height));
Segment[2] := PointF(position.X + GetX(7.6, Width),
position.Y + GetY(11.9, height));
Segment[3] := PointF(position.X + GetX(8.2, Width),
position.Y + GetY(7.7, height));
Segment[4] := Segment[0];

if (IsNumberAvailable(number, [0, 1, 3, 4, 5, 6, 7, 8, 9])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;

Canvas.FillPolygon(Segment, 1);

// Segment D
Segment[0] := PointF(position.X + GetX(7.4, Width),
position.Y + GetY(12.1, height));
Segment[1] := PointF(position.X + GetX(8.4, Width),
position.Y + GetY(13, height));
Segment[2] := PointF(position.X + GetX(1.3, Width),
position.Y + GetY(13, height));
Segment[3] := PointF(position.X + GetX(2.2, Width),
position.Y + GetY(12.1, height));
Segment[4] := Segment[0];

if (IsNumberAvailable(number, [0, 2, 3, 5, 6, 8, 9])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;

Canvas.FillPolygon(Segment, 1);

// Segment E
Segment[0] := PointF(position.X + GetX(2.2, Width),
position.Y + GetY(11.8, height));
Segment[1] := PointF(position.X + GetX(1, Width),
position.Y + GetY(12.7, height));
Segment[2] := PointF(position.X + GetX(1.7, Width),
position.Y + GetY(7.2, height));
Segment[3] := PointF(position.X + GetX(2.8, Width),
position.Y + GetY(7.7, height));
Segment[4] := Segment[0];
if (IsNumberAvailable(number, [0, 2, 6, 8])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;

Canvas.FillPolygon(Segment, 1);

// Segment F
Segment[0] := PointF(position.X + GetX(3, Width),
position.Y + GetY(6.4, height));
Segment[1] := PointF(position.X + GetX(1.8, Width),
position.Y + GetY(6.8, height));
Segment[2] := PointF(position.X + GetX(2.6, Width),
position.Y + GetY(1.3, height));
Segment[3] := PointF(position.X + GetX(3.6, Width),
position.Y + GetY(2.2, height));
Segment[4] := Segment[0];
if (IsNumberAvailable(number, [0, 4, 5, 6, 7, 8, 9])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;
Canvas.FillPolygon(Segment, 1);

// Segment G
setlength(Segment, 7);
Segment[0] := PointF(position.X + GetX(2, Width),
position.Y + GetY(7, height));
Segment[1] := PointF(position.X + GetX(3.1, Width),
position.Y + GetY(6.5, height));
Segment[2] := PointF(position.X + GetX(8.3, Width),
position.Y + GetY(6.5, height));
Segment[3] := PointF(position.X + GetX(9, Width),
position.Y + GetY(7, height));
Segment[4] := PointF(position.X + GetX(8.2, Width),
position.Y + GetY(7.5, height));
Segment[5] := PointF(position.X + GetX(2.9, Width),
position.Y + GetY(7.5, height));
Segment[6] := Segment[0];
if (IsNumberAvailable(number, [2, 3, 4, 5, 6, 8, 9, -1])) then
Canvas.Fill.Color := fillpen
else
Canvas.Fill.Color := outline;

Canvas.FillPolygon(Segment, 1);

// Draw decimal point
if dp then
begin
Canvas.Fill.Color := fillpen;
Canvas.FillEllipse(RectF(position.X + GetX(10, Width), position.Y + GetY(12,
height), position.X + GetX(10, Width) + Width / 7, position.Y + GetY(12,
height) + Width / 7), 1);
end;
end;

procedure TGauge.Paint;
var
Center: TPointF;
w: Single;
begin
Center := PointF(Width / 2, height / 2);
w := 0.95 * Width;

DrawBackground(Canvas, w, Center);
if FThreshHold >= FMinValue then
DrawPointer(Canvas, w, Center, True);
DrawPointer(Canvas, w, Center);
DrawCenterPoint(Canvas, w, Center);
DrawGloss(Canvas, w, Center);
end;

procedure TGauge.SetFlatMode(const Value: Boolean);
begin
if FFlatMode <> Value then
begin
FFlatMode := Value;
// Repaint;
end;
end;

procedure TGauge.SetCurrentValue(const Value: Single);
begin
if abs(FCurrentValue - Value) >= 0.1 then
begin
FCurrentValue := Value;
if (CaptureThresh) and (FThreshHold < Value) then
FThreshHold := Value;

// Repaint;
end;
end;

procedure TGauge.ResetThreshold;
begin
CaptureThresh := false;
FThreshHold := FMinValue - 1;
// Repaint;
end;

end.

Gauge in Firemonkey - Delphi-PRAXiS (2024)

References

Top Articles
How Craigslist Works
Oklahoma Inmate Search, Jail Rosters
Friskies Tender And Crunchy Recall
Places 5 Hours Away From Me
Kevin Cox Picks
Craigslist Monterrey Ca
Faridpur Govt. Girls' High School, Faridpur Test Examination—2023; English : Paper II
Wordscapes Level 5130 Answers
Santa Clara College Confidential
Craigslist Kennewick Pasco Richland
Bloxburg Image Ids
Kris Carolla Obituary
What's Wrong with the Chevrolet Tahoe?
Find your energy supplier
MindWare : Customer Reviews : Hocus Pocus Magic Show Kit
Steamy Afternoon With Handsome Fernando
Bcbs Prefix List Phone Numbers
Arre St Wv Srj
Voy Boards Miss America
Jang Urdu Today
ELT Concourse Delta: preparing for Module Two
Ge-Tracker Bond
Marine Forecast Sandy Hook To Manasquan Inlet
Diakimeko Leaks
Menus - Sea Level Oyster Bar - NBPT
Elbert County Swap Shop
Bento - A link in bio, but rich and beautiful.
Tinyzonehd
The Powers Below Drop Rate
Harrison 911 Cad Log
Chelsea Hardie Leaked
N.J. Hogenkamp Sons Funeral Home | Saint Henry, Ohio
Lincoln Financial Field, section 110, row 4, home of Philadelphia Eagles, Temple Owls, page 1
Kltv Com Big Red Box
Teenage Jobs Hiring Immediately
Craigslist West Seneca
American Bully Xxl Black Panther
Pro-Ject’s T2 Super Phono Turntable Is a Super Performer, and It’s a Super Bargain Too
Sas Majors
The best specialist spirits store | Spirituosengalerie Stuttgart
Pekin Soccer Tournament
Pike County Buy Sale And Trade
Citizens Bank Park - Clio
Eat Like A King Who's On A Budget Copypasta
Brother Bear Tattoo Ideas
Top 1,000 Girl Names for Your Baby Girl in 2024 | Pampers
Greg Steube Height
Gw2 Support Specter
Meee Ruh
Automatic Vehicle Accident Detection and Messageing System – IJERT
St Als Elm Clinic
Karen Kripas Obituary
Latest Posts
Article information

Author: Sen. Emmett Berge

Last Updated:

Views: 5545

Rating: 5 / 5 (80 voted)

Reviews: 95% of readers found this page helpful

Author information

Name: Sen. Emmett Berge

Birthday: 1993-06-17

Address: 787 Elvis Divide, Port Brice, OH 24507-6802

Phone: +9779049645255

Job: Senior Healthcare Specialist

Hobby: Cycling, Model building, Kitesurfing, Origami, Lapidary, Dance, Basketball

Introduction: My name is Sen. Emmett Berge, I am a funny, vast, charming, courageous, enthusiastic, jolly, famous person who loves writing and wants to share my knowledge and understanding with you.