mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-06-18 18:28:15 +02:00
300 lines
7.2 KiB
ObjectPascal
300 lines
7.2 KiB
ObjectPascal
{
|
|
This file is part of the Free Component Library.
|
|
Copyright (c) 2017 Michael Van Canneyt, member of the Free Pascal development team
|
|
|
|
Auxiliary class to draw a ruler.
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
**********************************************************************}
|
|
unit fpreportdrawruler;
|
|
|
|
{$mode objfpc}{$H+}
|
|
|
|
interface
|
|
|
|
uses
|
|
Types,Classes, SysUtils, Controls, Graphics;
|
|
|
|
type
|
|
TRulerUnits = (ruPx,ruIn,ruPt,ruM,ruDm,ruCm,ruMm);
|
|
TRulerType = (rtTop,rtLeft,rtBottom,rtRight);
|
|
|
|
{ TDrawRuler }
|
|
|
|
TDrawRuler = class(TPersistent)
|
|
private
|
|
FBoundsRect: TRect;
|
|
FCanvas: TCanvas;
|
|
FColor: TColor;
|
|
FDPI: Integer;
|
|
FFont: TFont;
|
|
FType : TRulerType;
|
|
FUnits : TRulerUnits;
|
|
FTickColor : TColor;
|
|
FMajorTicks : Double;
|
|
FPPU : Double;
|
|
FZeroOffset : Integer;
|
|
FMaxTickLength : Integer;
|
|
procedure DrawHTicks(tkStep: single);
|
|
procedure DrawVTicks(tkStep: single);
|
|
procedure SetBoundsRect(AValue: TRect);
|
|
procedure SetDPI(AValue: Integer);
|
|
procedure SetFont(AValue: TFont);
|
|
{ Protected declarations }
|
|
procedure SetRulerType(AType: TRulerType);
|
|
procedure SetRulerUnits(AUnits: TRulerUnits);
|
|
protected
|
|
procedure RecalcParams;
|
|
public
|
|
{ Public declarations }
|
|
constructor Create(ACanvas: TCanvas);
|
|
Destructor Destroy; override;
|
|
function Scale(AValue: Double): Integer;
|
|
function HorizontalRuler: Boolean;
|
|
procedure PaintRuler;
|
|
Property Canvas : TCanvas Read FCanvas;
|
|
Property BoundsRect : TRect Read FBoundsRect Write SetBoundsRect;
|
|
property RulerType: TRulerType read FType write SetRulerType;
|
|
property RulerUnits: TRulerUnits read FUnits write SetRulerUnits;
|
|
property TickColor: TColor read FTickColor write FTickColor;
|
|
Property ZeroOffset: Integer read FZeroOffset write FZeroOffset;
|
|
property Font : TFont Read FFont Write SetFont;
|
|
property Color : TColor Read FColor Write FCOlor;
|
|
Property DPI : Integer Read FDPI Write SetDPI;
|
|
end;
|
|
|
|
implementation
|
|
|
|
function PixelsPerUnit(DPI : Integer; AUnit: TRulerUnits): Single;
|
|
|
|
const
|
|
m2i = 39.3700787; // Inches in a meter
|
|
|
|
begin
|
|
Result:=DPI;
|
|
case AUnit of
|
|
ruPx : Result:=1;
|
|
ruIn : ;
|
|
ruPt : Result:=Result/12;
|
|
ruM : Result:=Result*m2i;
|
|
ruDM : Result:=Result*(m2i/10);
|
|
ruCM : Result:=Result*(m2i/100);
|
|
ruMM : Result:=Result*(m2i/1000);
|
|
end;
|
|
end;
|
|
|
|
constructor TDrawRuler.Create(ACanvas: TCanvas);
|
|
begin
|
|
FCanvas:=ACanvas;
|
|
FFont:=TFont.Create;
|
|
Color:=clWhite;
|
|
FTickColor:=cldkGray;
|
|
FType:=rtTop;
|
|
FUnits:=ruCm;
|
|
FZeroOffset:=0;
|
|
FDPI:=96;
|
|
RecalcParams;
|
|
end;
|
|
|
|
destructor TDrawRuler.Destroy;
|
|
begin
|
|
FreeAndNil(FFont);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TDrawRuler.SetFont(AValue: TFont);
|
|
begin
|
|
if FFont=AValue then Exit;
|
|
FFont.Assign(AValue);
|
|
end;
|
|
|
|
procedure TDrawRuler.SetBoundsRect(AValue: TRect);
|
|
begin
|
|
if EqualRect(FBoundsRect,AValue) then Exit;
|
|
FBoundsRect:=AValue;
|
|
RecalcParams;
|
|
end;
|
|
|
|
procedure TDrawRuler.SetDPI(AValue: Integer);
|
|
begin
|
|
if FDPI=AValue then Exit;
|
|
FDPI:=AValue;
|
|
end;
|
|
|
|
procedure TDrawRuler.SetRulerType(AType: TRulerType);
|
|
begin
|
|
if FType=AType then Exit;
|
|
FType:=AType;
|
|
end;
|
|
|
|
procedure TDrawRuler.SetRulerUnits(AUnits: TRulerUnits);
|
|
begin
|
|
if FUnits=AUnits then Exit;
|
|
FUnits:=AUnits;
|
|
RecalcParams;
|
|
end;
|
|
|
|
|
|
Function TDrawRuler.HorizontalRuler : Boolean;
|
|
|
|
begin
|
|
Result:=RulerType in [rtTop,rtBottom];
|
|
end;
|
|
|
|
procedure TDrawRuler.RecalcParams;
|
|
var I:Integer;
|
|
begin
|
|
FPPU:=PixelsPerUnit(DPI,FUnits);
|
|
FMajorTicks:=(DPI/FPPU);
|
|
I:=Trunc(FMajorTicks);
|
|
case I of
|
|
0: begin
|
|
FMajorTicks:=Int(FMajorTicks/0.05+0.5)*0.05 ; // to the nearest 5/100
|
|
if FMajorTicks=0 then FMajorTicks:=0.01; // we are to close to zero
|
|
end;
|
|
1..4: FMajorTicks:=Int(FMajorTicks); // to the nearest int
|
|
5..9: FMajorTicks:=Int(FMajorTicks/5+0.5)*5; // to the nearest 5
|
|
10..MaxInt: FMajorTicks:=Int(FMajorTicks/10+0.5)*10 // to the nearest 10;
|
|
end;
|
|
if HorizontalRuler then
|
|
begin
|
|
FMaxTickLength:=BoundsRect.Bottom-BoundsRect.Top - Canvas.TextHeight('W')- 2
|
|
end
|
|
else
|
|
begin
|
|
FMaxTickLength:=BoundsRect.Right-BoundsRect.Left - Canvas.TextHeight('W')- 2;
|
|
end;
|
|
end;
|
|
|
|
function TDrawRuler.Scale(AValue: Double): Integer;inline;
|
|
begin
|
|
Result:=Round(AValue * FPPU);
|
|
end;
|
|
|
|
procedure TDrawRuler.DrawHTicks(tkStep: single);
|
|
var
|
|
w,h,tkCount,tkLen,tkPos,y1,y2: Integer;
|
|
tkUnits : Single;
|
|
s : String;
|
|
|
|
begin
|
|
tkUnits:=0;
|
|
tkCount:=0;
|
|
if RulerType=rtTop then
|
|
y1:=FBoundsRect.Top
|
|
else
|
|
y1:=FBoundsRect.Bottom;
|
|
tkPos:=FBoundsRect.Left+FZeroOffset;
|
|
While (tkPos>=FBoundsRect.Left) and (tkPos<=FBoundsRect.Right) do
|
|
begin
|
|
case tkCount mod 10 of
|
|
0: tkLen:=FMaxTickLength;
|
|
5: tkLen:=FMaxTickLength div 2;
|
|
else
|
|
tkLen:= FMaxTickLength div 4;
|
|
end;
|
|
if RulerType=rtTop then
|
|
y2:=y1+tkLen
|
|
else
|
|
y2:=y1-tkLen;
|
|
Canvas.Line(tkPos,y1,tkPos,y2);
|
|
if (tkCount mod 10=0) then
|
|
begin
|
|
S:=FloatToStr(Round((tkUnits)*100)/100);
|
|
w:=Canvas.TextWidth(S);
|
|
H:=Canvas.TextHeight(S);
|
|
Canvas.TextRect(BoundsRect,tkPos-W div 2,BoundsRect.Bottom-H-2,S);
|
|
end;
|
|
tkUnits:=tkUnits+tkStep;
|
|
tkPos:=FBoundsRect.Left+FZeroOffset+Scale(tkUnits);
|
|
Inc(tkCount);
|
|
end
|
|
end;
|
|
|
|
procedure TDrawRuler.DrawVTicks(tkStep: single);
|
|
var
|
|
tkCount,tkLen,tkPos,x1,x2: Integer;
|
|
tkUnits : Single;
|
|
s : String;
|
|
E : TSize;
|
|
|
|
begin
|
|
tkUnits:=0;
|
|
tkCount:=0;
|
|
if RulerType=rtLeft then
|
|
x1:=FBoundsRect.Left
|
|
else
|
|
x1:=FBoundsRect.Right;
|
|
tkPos:=FBoundsRect.Top+FZeroOffset;
|
|
While (tkPos>=FBoundsRect.Top) and (tkPos<=FBoundsRect.Bottom) do
|
|
begin
|
|
case tkCount mod 10 of
|
|
0: tkLen:=FMaxTickLength;
|
|
5: tkLen:=FMaxTickLength div 2;
|
|
else
|
|
tkLen:= FMaxTickLength div 4;
|
|
end;
|
|
if RulerType=rtLeft then
|
|
x2:=x1+tkLen
|
|
else
|
|
x2:=x1-tkLen;
|
|
Canvas.Line(x1,tkPos,x2,tkPos);
|
|
if (tkCount mod 10=0) then
|
|
begin
|
|
S:=FloatToStr(Round((tkUnits)*100)/100);
|
|
Canvas.Font.Orientation:=0;
|
|
E:=Canvas.TextExtent(S);
|
|
Canvas.Font.Orientation:=900;
|
|
// Unfortunataly, TextRect does not work with fonts that are oriented. So we set the cliprect
|
|
Canvas.ClipRect:=BoundsRect;
|
|
Canvas.Clipping:=True;
|
|
Canvas.TextOut(BoundsRect.Right-E.cy-2,tkPos+(e.cx div 2),S);
|
|
Canvas.Font.Orientation:=0;
|
|
Canvas.Clipping:=False;
|
|
end;
|
|
tkUnits:=tkUnits+tkStep;
|
|
tkPos:=FBoundsRect.Top+FZeroOffset+Scale(tkUnits);
|
|
Inc(tkCount);
|
|
end
|
|
end;
|
|
|
|
procedure TDrawRuler.PaintRuler;
|
|
|
|
Var
|
|
T : TFont;
|
|
|
|
begin
|
|
Canvas.Brush.Color:=Color;
|
|
Canvas.Pen.Color:=FTickColor;
|
|
Canvas.Pen.Width:=1;
|
|
Canvas.Rectangle(BoundsRect);
|
|
T:=TFont.Create;
|
|
try
|
|
T.Assign(Canvas.Font);
|
|
Canvas.Font:=Font;
|
|
if HorizontalRuler then
|
|
begin
|
|
DrawHTicks(FMajorTicks/10);
|
|
DrawHTicks(-FMajorTicks/10);
|
|
end
|
|
else
|
|
begin
|
|
DrawVTicks(FMajorTicks/10);
|
|
DrawVTicks(-FMajorTicks/10);
|
|
end;
|
|
finally
|
|
Canvas.Font.Assign(T);
|
|
FreeAndNil(T);
|
|
end;
|
|
end;
|
|
|
|
|
|
end.
|
|
|