{****************************************************
 This file is part of the Eye Candy Controls (EC-C)
 
  Copyright (C) 2013 Vojtěch Čihák, Czech Republic
 
  This library is free software.

  See the file COPYING.LGPL.txt, 
  included in this distribution,
  for details about the license.
****************************************************}   

unit ECRuler;
{$mode objfpc}{$H+}  

//{$DEFINE DBGRULER}  {don't remove, just comment}

interface

uses
  Classes, SysUtils, Controls, Graphics, ExtCtrls, ECScale, ECTypes, Math, LCLIntf, 
  LMessages, {$IFDEF DBGRULER} LCLProc, {$ENDIF} LCLType, LResources, Themes, Types;

type 
  {$PACKENUM 2}
  TPointerMode = (epmNone, epmFixed, epmMovable);
  TPointerStyle = (epsSimple, epsDashed, epsDotted);
  { Event }
  TOnChangePosition = procedure(Sender: TObject; APosition: Double) of object;
  
  { TECRulerScale }
  TECRulerScale = class(TCustomECScale)
  protected const
    cDefTickAlign = etaInner;
    cDefValueVisible = evvValues;
  public
    constructor Create(AParent: TControl);
  published
    property DateTimeFormat;
    property Digits;
   { property FontOrientation; }
    property LogarithmBase;
    property Max;
    property Min;
    property ScaleType;
    property Text;
    property TickAlign default cDefTickAlign;
    property TickColor;
    property TickDesign;
    property TickIndent default 0;
    property TickLength;
    property TickLongValue;
    property TickMiddleValue;
    property TickShortValue;
    property TickVisible;
    property ValueDisplay;
    property ValueFormat;
    property ValueIndent;
    property ValueShift;
    property ValueVisible default cDefValueVisible; 
    property OnPrepareValue; 
  end;    
  
  { TCustomECRuler }
  TCustomECRuler = class(TECBaseControl)
  private
    FCaptionAlign: SmallInt;
    FCaptionPos: TBasicPos;
    FIndentBottomRight: Integer;
    FIndentTopLeft: Integer;
    FMouseCoord: Integer;
    FOnChangePosition: TOnChangePosition;
    FPointerColor: TColor;
    FPointerMode: TPointerMode;
    FPointerStyle: TPointerStyle;
    FPointerWidth: SmallInt;
    FPositionToHint: Boolean;
    FReversed: Boolean;
    FScale: TECRulerScale;
    FScaleFontOptions: TFontOptions;
    FScalePos: TBasicPos;
    FTransparent: Boolean;
    function GetMax: Double;
    function GetMin: Double; 
    function GetPosition: Double;
    procedure SetCaptionAlign(AValue: SmallInt);
    procedure SetCaptionPos(AValue: TBasicPos);
    procedure SetIndentBottomRight(AValue: Integer);
    procedure SetIndentTopLeft(AValue: Integer);
    procedure SetMax(AValue: Double);
    procedure SetMin(AValue: Double);
    procedure SetPointerColor(AValue: TColor);
    procedure SetPointerMode(AValue: TPointerMode);
    procedure SetPointerStyle(AValue: TPointerStyle);
    procedure SetPointerWidth(AValue: SmallInt);
    procedure SetPosition(AValue: Double);
    procedure SetPositionToHint(AValue: Boolean);
    procedure SetReversed(AValue: Boolean);
    procedure SetScalePos(AValue: TBasicPos);  
    procedure SetTransparent(AValue: Boolean);
  protected const
    cDefPointerMode = epmMovable;
    cDefPointerWidth = 1; 
  protected
    Background: TBitmap;
    CurrInvRect: TRect;
    FullBorderWidth: SmallInt;
    PointerOverlay: Integer;
    RedrawPointer: procedure(ACoord: Integer) of object;
    ScaleLength: Double;
    ScalePxLength, ScalePxStart: Integer;
    TimeFormat: TFormatSettings;
    WasEnabled: Boolean;  { state of IsEnabled from previous Paint }
    procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: Integer;
                                     {%H-}WithThemeSpace: Boolean); override;
    procedure Calculate;
    procedure CMColorChanged(var {%H-}Message: TLMessage); message CM_COLORCHANGED;
    procedure CMParentColorChanged(var Message: TLMessage); message CM_PARENTCOLORCHANGED;
    procedure DrawBackground;
    procedure DrawScaleAndCaption(ACanvas: TCanvas);
    procedure FontChanged(Sender: TObject); override;
    procedure InvalidateCustomRect({%H-}AMove: Boolean); override;
    function MouseCoordToPosition(AMouseCoord: Integer): Double; inline;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure OrientationChanged(AValue: TObjectOrientation); override;
    procedure Paint; override;
    procedure RecalcRedraw; override;				
    procedure Redraw3DColorAreas; override; 
    procedure RedrawHorizontal(X: Integer);
    procedure RedrawVertical(Y: Integer);
    procedure SetPointerPenStyle;
    procedure TextChanged; override;
    procedure WMSize(var Message: TLMSize); message LM_SIZE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure BeginUpdate; override;
    procedure EndUpdate(Recalculate: Boolean=True); override;
    procedure Redraw; override;
    procedure SetMouseCoord(AValue: Integer);
    property CaptionAlign: SmallInt read FCaptionAlign write SetCaptionAlign default 0;
    property CaptionPos: TBasicPos read FCaptionPos write SetCaptionPos default ebpBottomRight;
    property IndentBottomRight: Integer read FIndentBottomRight write SetIndentBottomRight default 0;
    property IndentTopLeft: Integer read FIndentTopLeft write SetIndentTopLeft default 0;
    property Max: Double read GetMax write SetMax stored False;
    property Min: Double read GetMin write SetMin stored False;
    property MouseCoord: Integer read FMouseCoord write SetMouseCoord;
    property PointerColor: TColor read FPointerColor write SetPointerColor default clDefault;
    property PointerMode: TPointerMode read FPointerMode write SetPointerMode default cDefPointerMode;
    property PointerStyle: TPointerStyle read FPointerStyle write SetPointerStyle default epsSimple;
    property PointerWidth: SmallInt read FPointerWidth write SetPointerWidth default cDefPointerWidth;
    property Position: Double read GetPosition write SetPosition stored False;
    property PositionToHint: Boolean read FPositionToHint write SetPositionToHint default False;
    property Reversed: Boolean read FReversed write SetReversed default False;
    property Scale: TECRulerScale read FScale write FScale;
    property ScaleFontOptions: TFontOptions read FScaleFontOptions write FScaleFontOptions;
    property ScalePos: TBasicPos read FScalePos write SetScalePos default ebpTopLeft;
    property Transparent: Boolean read FTransparent write SetTransparent default False;
    property OnChangePosition: TOnChangePosition read FOnChangePosition write FOnChangePosition;
  end;

  TECRuler = class(TCustomECRuler)
  published
    property Align;
    property Anchors;
    property AutoSize default True;
    property BevelInner;
    property BevelOuter;
    property BevelSpace;
    property BevelWidth;
    property BorderSpacing;
    property Caption;
    property CaptionAlign;
    property CaptionPos;
    property Color;
    property Color3DDark;
    property Color3DLight;
    property Constraints;
    property Enabled;
    property Font;
    property IndentBottomRight;
    property IndentTopLeft;
    property Max;
    property Min;
    property Orientation default eooHorizontal;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PointerColor;
    property PointerMode;
    property PointerStyle;
    property PointerWidth;
    property PopupMenu;
    property Position;
    property PositionToHint;
    property Reversed;
    property Scale;
    property ScaleFontOptions;
    property ScalePos;
    property ShowHint;
    property Style default eosPanel;
    property Transparent;
    property Visible;
    property OnChangeBounds;
    property OnChangePosition;
    property OnClick;
    property OnContextPopup;
    property OnDblClick;
    property OnMouseDown;
    property OnMouseEnter;
    property OnMouseLeave;
    property OnMouseMove;
    property OnMouseUp;
    property OnResize;
  end;

procedure Register;

implementation

{ TECRulerScale }

constructor TECRulerScale.Create(AParent: TControl);
begin
  inherited Create(AParent);
  FTickAlign := cDefTickAlign;
  FTickIndent := 0;
  FValueVisible := cDefValueVisible;  
end;

{ TCustomECRuler }

constructor TCustomECRuler.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csNoFocus]
                               - [csSetCaption];
  FCaptionPos := ebpBottomRight;
  FMouseCoord := low(Integer);
  FOrientation := eooHorizontal;
  RedrawPointer := @RedrawHorizontal;
  FPointerColor := clDefault;
  FPointerMode := cDefPointerMode;
  PointerWidth := cDefPointerWidth;  {Set PointerOverlay}
  FStyle := eosPanel;
  AutoSize := True;
  TabStop := False;
  FScaleFontOptions := TFontOptions.Create(self);
  with FScaleFontOptions do
    begin
      FontSize := 7;
      OnRecalcRedraw := @self.RecalcRedraw;
      OnRedraw := @self.Redraw;
    end;
  FScale := TECRulerScale.Create(self);
  with FScale do
    begin
      OnRecalcRedraw := @self.RecalcRedraw;
      OnRedraw := @self.Redraw;
    end;
  Background := TBitmap.Create;
  with Background do
    begin
      Transparent := True;
      TransparentMode := tmFixed;
    end;
  SetInitialBounds(0, 0, 320, 50);
  RedrawMode := ermRecalcRedraw;
end;

destructor TCustomECRuler.Destroy;
begin
  FreeAndNil(Background);
  FreeAndNil(FScale);
  FreeAndNil(FScaleFontOptions);
  inherited Destroy;
end;

procedure TCustomECRuler.CalculatePreferredSize(var PreferredWidth, 
            PreferredHeight: Integer; WithThemeSpace: Boolean);
var aSize: Integer;
begin
  Canvas.Font.Size := FScaleFontOptions.FontSize;
  Canvas.Font.Style := FScaleFontOptions.FontStyles;
  aSize := 2*GetBorderWidth + FScale.GetPreferredSize(Canvas, Orientation=eooHorizontal, True, True);
  if Orientation = eooHorizontal then
    begin
      PreferredHeight := aSize;
      PreferredWidth := 0;      
    end else
    begin
      PreferredHeight := 0;
      PreferredWidth := aSize;      
    end;
end;

procedure TCustomECRuler.BeginUpdate;
begin
  inherited BeginUpdate;
  FScale.BeginUpdate;
end;

procedure TCustomECRuler.Calculate;
var aBorderWidth, aLength: Integer;
begin
  aBorderWidth := GetBorderWidth;
  FullBorderWidth := aBorderWidth;
  if Orientation = eooHorizontal 
    then aLength := Width
    else aLength := Height;
  aLength := aLength - IndentTopLeft - IndentBottomRight - 2*aBorderWidth;
  ScaleLength := Max - Min;
  ScalePxLength := aLength;
  ScalePxStart := IndentTopLeft + aBorderWidth;
  FScale.CalcTickPosAndValues(aLength, Reversed);
end;

procedure TCustomECRuler.CMColorChanged(var Message: TLMessage);
begin
  Redraw;
end;  

procedure TCustomECRuler.CMParentColorChanged(var Message: TLMessage);
begin
  inherited CMParentColorChanged(Message);
  if (Style = eosPanel) and (Color = clDefault) then Redraw;
end;  

procedure TCustomECRuler.DrawBackground;
var aColor: TColor;
begin
  {$IFDEF DBGRULER} DebugLn('ECRuler DrawBackground'); {$ENDIF}
  Background.SetSize(Width, Height);          
  aColor := ColorToRGB(GetColorResolvingDefault(Color, Parent.Brush.Color));
  if (aColor and $FF) > 0
    then dec(aColor)
    else inc(aColor);
  Background.TransparentColor := aColor;
  Background.TransparentClear;
  case Style of
    eosButton: Background.Canvas.DrawButtonBackground(ClientRect, True);
    eosPanel: Background.Canvas.DrawPanelBackGround(ClientRect, BevelInner, BevelOuter,
                BevelSpace, BevelWidth, Color3DDark, Color3DLight, 
                GetColorResolvingDefault(Color, Parent.Brush.Color));
  end;
  DrawScaleAndCaption(Background.Canvas);
  SetPointerPenStyle;
end;

procedure TCustomECRuler.DrawScaleAndCaption(ACanvas: TCanvas);
const cIndent = 3;
var aFlags, aHelpFlag: Cardinal;
    i, j, aAbsCaptionIndent, aBorderWidth, aBottom, aRight: Integer;
    aRect: TRect;
    aSize: TSize;
begin
  aBorderWidth := GetBorderWidth;
  ACanvas.Font.Assign(Font);
  if Caption <> '' then
    begin
      ACanvas.Font.Color := GetColorResolvingDefault(ACanvas.Font.Color, clBtnText);
      aFlags := DT_NOPREFIX or DT_MODIFYSTRING or DT_END_ELLIPSIS or DT_SINGLELINE;
      if IsRightToLeft then aFlags := aFlags or DT_RTLREADING;
      aHelpFlag := DT_TOP;
      aBottom := Height;
      aRight := Width;   
      aSize := ACanvas.TextExtent(Caption);
      aAbsCaptionIndent := abs(CaptionAlign);
      if Orientation = eooHorizontal then
        begin  { Horizontal }
          if FScale.TickVisible > etvNone then
            begin
              if ScalePos = ebpTopLeft 
                then j := Math.max(aBorderWidth + FScale.TickIndent, cIndent)
                else j := aBottom - Math.max(FScale.TickIndent + aBorderWidth, cIndent) - aSize.cy;
            end else
            begin
              if FScalePos = ebpTopLeft 
                then j := Math.max(aBorderWidth + FScale.ValueIndent, cIndent)
                else j := aBottom - Math.max(aBorderWidth + FScale.ValueIndent, cIndent) - aSize.cy;
            end;
          if CaptionPos = ebpTopLeft then 
            begin
              i := aBorderWidth;
              aRight := ScalePxStart;
              case CaptionAlign of
                low(CaptionAlign)..-1: inc(i, aAbsCaptionIndent);
                0: aHelpFlag := DT_CENTER;
                1..high(CaptionAlign): 
                  begin
                    aHelpFlag := DT_RIGHT;
                    dec(aRight, aAbsCaptionIndent);
                  end;
              end;
            end else 
            begin 
              i := ScalePxStart + ScalePxLength;
              dec(aRight, aBorderWidth);
              case CaptionAlign of
                low(SmallInt)..-1: 
                  begin
                    aHelpFlag := DT_RIGHT;
                    dec(aRight, aAbsCaptionIndent);
                  end;
                0: aHelpFlag := DT_CENTER;
                1..high(CaptionAlign): inc(i, aAbsCaptionIndent);
              end;
            end;
          dec(aBottom, aBorderWidth);
        end else                                               
        begin  { Vertical }
          if FScale.TickVisible > etvNone then
            begin
              if ScalePos = ebpTopLeft 
                then i := Math.max(aBorderWidth + FScale.TickIndent, cIndent)
                else i := aRight - Math.max(FScale.TickIndent + aBorderWidth, cIndent) - aSize.cx;
            end else
            begin
              if ScalePos = ebpTopLeft 
                then i := Math.max(aBorderWidth + FScale.ValueIndent, cIndent)
                else i := aRight - Math.max(aBorderWidth + FScale.ValueIndent, cIndent) - aSize.cx;
            end;
          if CaptionPos = ebpTopLeft then
            begin
              j := aBorderWidth;
              aBottom := ScalePxStart;
              case CaptionAlign of
                low(CaptionAlign)..-1: inc(j, aAbsCaptionIndent);
                0: aHelpFlag := DT_VCENTER;
                1..high(CaptionAlign): 
                  begin
                    aHelpFlag := DT_BOTTOM;
                    dec(aBottom, aAbsCaptionIndent);
                  end;
              end;
            end else
            begin
              j := ScalePxStart + ScalePxLength;
              dec(aBottom, aBorderWidth);
              case CaptionAlign of
                low(SmallInt)..-1: 
                  begin
                    aHelpFlag := DT_BOTTOM;
                    dec(aBottom, aAbsCaptionIndent);
                  end;
                0: aHelpFlag := DT_VCENTER;
                1..high(CaptionAlign): inc(j, aAbsCaptionIndent);
              end;   
            end;
          dec(aRight, aBorderWidth);
        end;
      aRect := Rect(i, j, aRight, aBottom);
      aFlags := aFlags or aHelpFlag;
      with ThemeServices do 
        DrawText(ACanvas, GetElementDetails(caThemedContent[caItemState[IsEnabled]]), 
          Caption, aRect, aFlags, 0);
    end; 
  ACanvas.Font.Color := GetColorResolvingDefault(FScaleFontOptions.FontColor, clBtnText);
  ACanvas.Font.Orientation := FScale.FontOrientation;
  ACanvas.Font.Size := FScaleFontOptions.FontSize;              
  ACanvas.Font.Style := FScaleFontOptions.FontStyles;
  if Orientation = eooHorizontal then
    begin
      if ScalePos = ebpTopLeft 
        then FScale.Draw(ACanvas, True, True, eopBottom, 
               Color3DDark, Color3DLight, Point(ScalePxStart, aBorderWidth - 1), [])
        else FScale.Draw(ACanvas, True, True, eopTop, 
               Color3DDark, Color3DLight, Point(ScalePxStart, Height - aBorderWidth), []);
    end else
    begin
      if ScalePos = ebpTopLeft 
        then FScale.Draw(ACanvas, True, True, eopRight, 
               Color3DDark, Color3DLight, Point(aBorderWidth - 1, ScalePxStart), [])     
        else FScale.Draw(ACanvas, True, True, eopLeft,
               Color3DDark, Color3DLight, Point(Width - aBorderWidth, ScalePxStart), []);
    end;                 
end;

procedure TCustomECRuler.EndUpdate(Recalculate: Boolean);
begin
  FScale.EndUpdate;
  inherited EndUpdate(Recalculate);
end;

procedure TCustomECRuler.FontChanged(Sender: TObject);
begin
  inherited FontChanged(Sender);
  RecalcRedraw;
end;                                                             

procedure TCustomECRuler.InvalidateCustomRect(AMove: Boolean);
begin 
end;

function TCustomECRuler.MouseCoordToPosition(AMouseCoord: Integer): Double;
begin
  Result := (AMouseCoord - ScalePxStart)*ScaleLength/(ScalePxLength - 1);
  if Reversed then Result := Max - Result;
end;   

procedure TCustomECRuler.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited MouseMove(Shift, X, Y);
  if (PointerMode = epmMovable) and WasEnabled then
    begin
      if Orientation = eooHorizontal
        then RedrawPointer(X)
        else RedrawPointer(Y);
      if PositionToHint then Hint := FScale.GetStringPosition(Position);  
    end;
end;

procedure TCustomECRuler.OrientationChanged(AValue: TObjectOrientation);
begin
  if AValue = eooHorizontal 
    then RedrawPointer := @RedrawHorizontal
    else RedrawPointer := @RedrawVertical;
  FMouseCoord := low(Integer);
  if not(csLoading in ComponentState) then SetBounds(Left, Top, Height, Width); 
  inherited OrientationChanged(AValue);
end;

procedure TCustomECRuler.Paint;
var bEnabled: Boolean;
    
  procedure DrawPointer;
  var aBorderWidth: SmallInt;
  begin
    aBorderWidth := FullBorderWidth + PointerOverlay;
    if Orientation = eooHorizontal 
      then Canvas.Line(MouseCoord, aBorderWidth + 1, MouseCoord, self.Height - aBorderWidth)
      else Canvas.Line(aBorderWidth + 1, MouseCoord, self.Width - aBorderWidth, MouseCoord);        
  end;
    
begin
  {$IFDEF DBGRULER} DebugLn('Ruler Paint'); {$ENDIF}
  inherited Paint;
  if RedrawMode = ermRecalcRedraw then Calculate;
  bEnabled := IsEnabled;
  if bEnabled <> WasEnabled then 
    begin
      RedrawMode := ermRedrawBkgnd; 
      CurrInvRect := ClientRect;  { the case that Position was changed when Disabled }
    end;
  if not Transparent then
    begin
      if RedrawMode >= ermRedrawBkgnd then DrawBackground;
      if RedrawMode >= ermFreeRedraw then Canvas.Draw(0, 0, Background);
      if bEnabled and (PointerMode > epmNone) then
        begin
          if RedrawMode < ermFreeRedraw then Canvas.CopyRect(FInvalidRect, Background.Canvas, FInvalidRect);
          DrawPointer;
        end;
      FInvalidRect := CurrInvRect;
    end else
    begin
      Canvas.Pen.Width:=1;
      DrawScaleAndCaption(Canvas);
      if bEnabled and (PointerMode > epmNone) then
        begin
          SetPointerPenStyle;
          DrawPointer;
        end;
    end;
  WasEnabled := bEnabled;
  RedrawMode := ermFreeRedraw;
end;

procedure TCustomECRuler.RecalcRedraw;
begin
  RedrawMode := ermRecalcRedraw;
  if UpdateCount = 0 then
    begin
      if AutoSize then
        begin
          InvalidatePreferredSize;
          AdjustSize;
        end;
      Invalidate;
    end;
end;

procedure TCustomECRuler.Redraw;
begin
  if RedrawMode <  ermRedrawBkgnd then RedrawMode := ermRedrawBkgnd;
  if UpdateCount = 0 then Invalidate;
end;

procedure TCustomECRuler.Redraw3DColorAreas;
begin
  Redraw;
end;

procedure TCustomECRuler.RedrawHorizontal(X: Integer);
var aRect: TRect;
    aBorderWidth, i: Integer;
begin
  if MouseCoord <> X then
    begin
      if RedrawMode <= ermFreeRedraw then RedrawMode := ermMoveKnob;
      i := PointerOverlay;
      aBorderWidth := FullBorderWidth;
      if (X >= aBorderWidth) and (X <= (Width - aBorderWidth)) then
        begin
          FMouseCoord := X;
          if assigned(FOnChangePosition) then FOnChangePosition(self, MouseCoordToPosition(X));
        end;
      if not Transparent then
        begin
          aRect := Rect(X - i, aBorderWidth, X + i, Height - aBorderWidth);  
          CurrInvRect := aRect;
          FInvalidRect.Left := Math.min(FInvalidRect.Left, aRect.Left);
          FInvalidRect.Right := Math.max(FInvalidRect.Right, aRect.Right);
          InvalidateRect(Handle, @FInvalidRect, False);
        end else
        Invalidate;
    end;
end;

procedure TCustomECRuler.RedrawVertical(Y: Integer);
var aRect: TRect;
    aBorderWidth, j: Integer;
begin
  if MouseCoord <> Y then
    begin
      if RedrawMode <= ermFreeRedraw then RedrawMode := ermMoveKnob;
      j := PointerOverlay;
      aBorderWidth := FullBorderWidth;
      if (Y >= aBorderWidth) and (Y <= (Height - aBorderWidth)) then 
        begin
          FMouseCoord := Y;   
          if assigned(FOnChangePosition) then FOnChangePosition(self, MouseCoordToPosition(Y));
        end;
      if not Transparent then
        begin     
          aRect := Rect(aBorderWidth, Y - j, Width - aBorderWidth, Y + j);
          CurrInvRect := aRect;
          FInvalidRect.Top := Math.min(FInvalidRect.Top, aRect.Top);
          FInvalidRect.Bottom := Math.max(FInvalidRect.Bottom, aRect.Bottom);
          InvalidateRect(Handle, @FInvalidRect, False);
        end else
        Invalidate;
    end;
end;

procedure TCustomECRuler.SetPointerPenStyle;
begin
  with Canvas do
    begin
      case FPointerStyle of
        epsSimple: Pen.Style := psSolid;
        epsDashed: Pen.Style := psDash;
        epsDotted: Pen.Style := psDot;
      end;
      Brush.Style := bsClear;  { necessary }
      Pen.Color := GetColorResolvingDefault(PointerColor, clBtnText);
      Pen.Width := PointerWidth;
    end;
end;

procedure TCustomECRuler.TextChanged;
begin
  inherited TextChanged;
  Redraw;
end;

procedure TCustomECRuler.WMSize(var Message: TLMSize);
begin
  inherited WMSize(Message);
  RedrawMode := ermRecalcRedraw;
  if UpdateCount = 0 then Invalidate;
end;

{ TCustomECRuler.Setters }

function TCustomECRuler.GetMax: Double;
begin
  Result := Scale.Max;
end;

function TCustomECRuler.GetMin: Double;
begin
  Result := Scale.Min;
end;     

function TCustomECRuler.GetPosition: Double;
begin
  Result := MouseCoordToPosition(MouseCoord)
end;

procedure TCustomECRuler.SetCaptionAlign(AValue: SmallInt);
begin
  if FCaptionAlign = AValue then exit;
  FCaptionAlign := AValue;
  if Caption <> '' then Redraw;
end;  

procedure TCustomECRuler.SetCaptionPos(AValue: TBasicPos);
begin
  if FCaptionPos = AValue then exit;
  FCaptionPos := AValue;
  if Caption <> '' then Redraw;
end;

procedure TCustomECRuler.SetIndentBottomRight(AValue: Integer);
begin
  if FIndentBottomRight = AValue then exit;
  FIndentBottomRight := AValue;
  RecalcRedraw;
end;

procedure TCustomECRuler.SetIndentTopLeft(AValue: Integer);
begin
  if FIndentTopLeft = AValue then exit;
  FIndentTopLeft := AValue;
  RecalcRedraw;
end;

procedure TCustomECRuler.SetMax(AValue: Double);
begin
  Scale.Max := AValue;
end;

procedure TCustomECRuler.SetMin(AValue: Double);
begin
  Scale.Min := AValue;
end;

procedure TCustomECRuler.SetMouseCoord(AValue: Integer);
begin
  if (PointerMode > epmNone) and WasEnabled then RedrawPointer(AValue);
  FMouseCoord := AValue;
  if PositionToHint then Hint := FScale.GetStringPosition(Position);    
end;

procedure TCustomECRuler.SetPointerColor(AValue: TColor);
begin
  if FPointerColor = AValue then exit;
  FPointerColor := AValue;
  SetPointerPenStyle;
  if PointerMode > epmNone then InvalidateNonUpdated;
end;

procedure TCustomECRuler.SetPointerMode(AValue: TPointerMode);
begin
  if FPointerMode = AValue then exit;
  FPointerMode := AValue;
  if AValue > epmNone then CurrInvRect := ClientRect;
  InvalidateNonUpdated;
end;

procedure TCustomECRuler.SetPointerStyle(AValue: TPointerStyle);
begin
  if FPointerStyle = AValue then exit;
  FPointerStyle := AValue;
  SetPointerPenStyle;
  if PointerMode > epmNone then InvalidateNonUpdated;
end;

procedure TCustomECRuler.SetPointerWidth(AValue: SmallInt);
begin
  if FPointerWidth = AValue then exit;
  FPointerWidth := AValue;
  PointerOverlay := 1 + AValue div 2;
  SetPointerPenStyle;
  if PointerMode > epmNone then InvalidateNonUpdated;
end;

procedure TCustomECRuler.SetPosition(AValue: Double);
var aCoord: Integer;
begin
  if Reversed then AValue := Max - AValue;
  aCoord := round(AValue*(ScalePxLength - 1) /ScaleLength) + ScalePxStart;
  if PositionToHint then Hint := FScale.GetStringPosition(AValue); 
  if (PointerMode > epmNone) and WasEnabled then RedrawPointer(aCoord);
end;

procedure TCustomECRuler.SetPositionToHint(AValue: Boolean);
begin
  if FPositionToHint = AValue then exit;   
  FPositionToHint := AValue;
  if AValue then Hint := FScale.GetStringPosition(Position); 
end;    

procedure TCustomECRuler.SetReversed(AValue: Boolean);
begin
  if FReversed = AValue then exit;
  FReversed := AValue;       
  RecalcRedraw;
end;

procedure TCustomECRuler.SetScalePos(AValue: TBasicPos);
begin
  if FScalePos = AValue then exit;  
  FScalePos := AValue;
  if (FScale.TickVisible > etvNone) or (FScale.ValueVisible > evvNone) then RecalcRedraw;
end;

procedure TCustomECRuler.SetTransparent(AValue: Boolean);
begin
  if FTransparent = AValue then exit;
  FTransparent := AValue;
  if not AValue then RedrawMode := ermRedrawBkgnd;
  InvalidateNonUpdated;  
end;

procedure Register;
begin
  {$I ecruler.lrs}
  RegisterComponents('EC-C', [TECRuler]);
end;

end.


