(* ImageEn Build 7.0.0.06.2637 @ 7-4-17 14:58:42.679 *) (* Copyright (c) 1998-2017 by Carlotta Calandra. All rights reserved. Copyright (c) 2011-2017 by Xequte Software. This software comes without express or implied warranty. In no case shall the author be liable for any damage or unwanted behavior of any computer hardware and/or software. Author grants you the right to include the component in your application, whether COMMERCIAL, SHAREWARE, or FREEWARE. ImageEn, IEvolution and ImageEn ActiveX may not be included in any commercial, shareware or freeware libraries or components. www.ImageEn.com *) (* File: iexRulers.pas Description: Provides rulers for use by TImageEnView and TRulerBox File version 1010 Doc revision 1002 *) unit iexRulers; {$R-} {$Q-} {$I ie.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, {$ifdef IEHASTYPES} Types, {$endif} iegdiplus; const IEMAXPOLYGLINES = 10; type TIEPolyg = array[0..IEMAXPOLYGLINES - 1] of TPoint; {!! TGripKind Declaration TGripKind = (gkTriangle, gkLeftTriangle, gkRightTriangle, gkArrow, gkArrow2, gkLine, gkNone); Description Item Description gkTriangle Triangle gkLeftTriangle Triangle pointing to the left gkRightTriangle Triangle pointing to the right gkArrow A standard arrow gkArrow2 A track bar style arrow gkLine Line only gkNone Grip is not visible
!!} TGripKind = (gkTriangle, gkLeftTriangle, gkRightTriangle, gkArrow, gkArrow2, gkLine, gkNone); {!! TGripsDir Declaration } TGripsDir = (gdUp, gdDown); {!!} {!! TGripsXDir Declaration } TGripsXDir = (gdLeft, gdRight); {!!} {!! TRulerDir Declaration } TRulerDir = (rdHorizontal, rdVertical); {!!} {!! TRulerDirs Declaration TRulerDirs = Set of ; !!} TRulerDirs = Set of TRulerDir; {!! TIERulerUnits Declaration } TIERulerUnits = (ieruPixels, ieruInches, ieruMillimeters, ieruCentimeters); {!!} {!! TIERulerSnapping Declaration TIERulerSnapping = (iesnNone, iesnSnapToTick, iesnSnapToLabel, iesnSnapToWholeNumber); Description Item Description iesnNone Do not adjust grip positions iesnSnapToTick Automatically move grips to the nearest tick iesnSnapToLabel Automatically move grips to the nearest label (long tick) iesnSnapToWholeNumber Automatically move grips to the nearest whole value on the ruler (e.g. move to 2.0 inches)
Default: iesnNone Example // Snap to the nearest label tick ImageEnView1.RulerParams.SnapGrips := iesnSnapToLabel; // Snap to the nearest whole number on the ruler ImageEnView1.RulerParams.SnapGrips := iesnSnapToWholeNumber; !!} TIERulerSnapping = (iesnNone, iesnSnapToTick, iesnSnapToLabel, iesnSnapToWholeNumber); {!! TIERulerPosBase Declaration } TIERulerPosBase = (ierbRuler, ierbBitmap, ierbScreen); {!!} {!! TRulerGripPosChangeEvent Declaration } TRulerGripPosChangeEvent = procedure(Sender: TObject; RulerDir: TRulerDir; Grip: integer; NewPos: Double) of object; {!!} {!! TRulerClickEvent Declaration } TRulerClickEvent = procedure(Sender: TObject; RulerDir: TRulerDir; Ps: double) of object; {!!} {!! TRulerGripClickEvent Declaration } TRulerGripClickEvent = procedure(Sender: TObject; RulerDir: TRulerDir; Grip: integer; GripPos: Double) of object; {!!} // Internal only TRulerSetGripPosEvent = procedure(Sender: TObject; var GripPos: double) of object; // Internal class for handling and display the rulers of TImageEnView and TRulerBox TIERuler = class private { Private declarations } fOwner: TControl; fBitmap: TBitmap; fBackground: TColor; fGrips: TList; // list of rips fGripBaseDim: integer; // base size of grip (triangles) fSelGrip: integer; // selected grip (-1=none) fSelGripSt: integer; // starting position during mouse-dragging fMX1, fMY1: integer; // initial mouse coordinate during mouse-dragging fGripsDir: TGripsDir; // direction for all grips fShowRuler: boolean; // ruler + numeric labels fViewPos: double; // starting ruler position fDPU: double; // DotPerUnit - relation between ruler and pixels fFrequency: double; // line frequency (Unit based) fLabelFreq: double; // label frequency (Unit based) fRulerColor: TColor; // ruler color fRulerDir: TRulerDir; // ruler orientation fViewMin, fViewMax: double; // Max and Min for fViewPos fFitInView: boolean; // adjust fDPU from fViewMin and fViewMax fHexLabels: boolean; // if true display labels in hex fMaxGripHeight: integer; fInverted: boolean; // ruler is inverted fScrollRate: double; // scroll rate fOffsetX, fOffsetY: integer; // horizontal or vertical offset fLabelPrecision: Integer; fMinLabelSpacing: Integer; fGripPenColor : TColor; fGripKindDefault: TGripKind; fGripColorDefault : TColor; fLockUpdateCount: Integer; // When > 0 updating is disabled fFont: TFont; fGripIndexOffset: Integer; // When used by a TImageEnView, grip 0 is used to show the cursor position. We hide this from the user by offsetting the grip indexes/count by 1 fShowBorder: Boolean; procedure SetBackground(bk: TColor); procedure SetGripsCount(v: integer); function GetGripsCount: integer; procedure SetGripsPos(i: integer; p: double); function GetGripsPos(i: integer): double; procedure SetGripsColor(i: integer; p: TColor); function GetGripsColor(i: integer): TColor; procedure SetGripBaseDim(v: integer); procedure SetGripsKind(i: integer; v: TGripKind); function GetGripsKind(i: integer): TGripKind; procedure SetGripsDir(v: TGripsDir); procedure SetShowRuler(v: boolean); procedure SetViewPos(v: double); procedure SetDPU(v: double); procedure SetFrequency(v: double); procedure SetLabelFreq(v: double); procedure SetRulerColor(v: TColor); procedure SetRulerDir(v: TRulerDir); procedure SetGripsMax(i: integer; v: double); procedure SetGripsMin(i: integer; v: double); function GetGripsMax(i: integer): double; function GetGripsMin(i: integer): double; procedure SetViewMin(v: double); procedure SetViewMax(v: double); procedure SetFitInView(v: boolean); procedure SetHexLabels(v: boolean); procedure SetInverted(v: boolean); procedure SetOffsetX(v: integer); procedure SetOffsetY(v: integer); procedure SetLabelPrecision(v: integer); procedure SetMinLabelSpacing(v: integer); procedure SetGripPenColor(const Value: TColor); procedure SetGripKindDefault(const Value: TGripKind); procedure SetGripColorDefault(const Value: TColor); function GetClickedGrip(x, y: integer): integer; procedure GetGripPoly(gn: integer; var poly: TIEPolyg); procedure GetGripRect(gn: integer; var rc: TRect); function GetRulerHeight: integer; procedure RepaintGrips; procedure RepaintRuler; procedure RepaintBorder; function GetXGripPos(gn: integer): integer; procedure AdjustGripLimits(gn: integer); procedure AdjustViewLimits; procedure SetShowBorder(const Value: boolean); protected { Protected declarations } procedure FontChange(Sender: TObject); public { Public declarations } // EVENTS fOnRulerGripPosChange: TRulerGripPosChangeEvent; fOnRulerGripClick: TRulerGripClickEvent; fOnRulerGripDblClick: TRulerGripClickEvent; fOnRulerClick: TRulerClickEvent; constructor Create(Owner: TControl); destructor Destroy; override; procedure Update(); procedure UpdateEx(RepaintAll, DoInvalidate : Boolean); procedure LockUpdate(); procedure UnlockUpdate(RepaintAll: Boolean = True; DoInvalidate: Boolean = True); property GripsPos[g: integer]: double read GetGripsPos write SetGripsPos; default; property GripsColor[g: integer]: TColor read GetGripsColor write SetGripsColor; property GripsKind[g: integer]: TGripKind read GetGripsKind write SetGripsKind; property GripsMin[g: integer]: double read GetGripsMin write SetGripsMin; property GripsMax[g: integer]: double read GetGripsMax write SetGripsMax; property ScrollRate: double read fScrollRate write fScrollRate; // Need to handle the following in objects that use this class procedure DrawToCanvas(Canvas: TCanvas; X, Y: Integer); procedure HandleMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HandleMouseMove(Shift: TShiftState; X, Y: Integer); procedure HandleMouseMoveEx(Shift: TShiftState; X, Y: Integer; SetGripCallBack: TRulerSetGripPosEvent); procedure HandleMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure UpdateSize(Width, Height: integer); property ViewPos: double read fViewPos write SetViewPos; property Background: TColor read fBackground write SetBackground default clBtnFace; property GripPenColor : TColor read fGripPenColor write SetGripPenColor default clWindowFrame; property GripBaseDim: integer read fGripBaseDim write SetGripBaseDim default 12; property GripsDir: TGripsDir read fGripsDir write SetGripsDir default gdUp; property ShowRuler: boolean read fShowRuler write SetShowRuler default true; property DotPerUnit: double read fDPU write SetDPU; property Frequency: double read fFrequency write SetFrequency; property LabelFrequency: double read fLabelFreq write SetLabelFreq; property RulerColor: TColor read fRulerColor write SetRulerColor default clBtnFace; property RulerDir: TRulerDir read fRulerDir write SetRulerDir default rdHorizontal; property ViewMin: double read fViewMin write SetViewMin; property ViewMax: double read fViewMax write SetViewMax; property LabelPrecision: integer read fLabelPrecision write SetLabelPrecision default 3; property MinLabelSpacing: integer read fMinLabelSpacing write SetMinLabelSpacing default 30; property GripKindDefault: TGripKind read fGripKindDefault write SetGripKindDefault default gkTriangle; property GripColorDefault: TColor read fGripColorDefault write SetGripColorDefault default clBtnFace; property OffsetX: integer read fOffsetX write SetOffsetX default 0; property OffsetY: integer read fOffsetY write SetOffsetY default 0; property MaxGripHeight: integer read fMaxGripHeight write fMaxGripHeight; property Inverted: boolean read fInverted write SetInverted default false; property FitInView: boolean read fFitInView write SetFitInView default false; property GripsCount: integer read GetGripsCount write SetGripsCount default 1; property HexLabels: boolean read fHexLabels write SetHexLabels default false; property ShowBorder : boolean read fShowBorder write SetShowBorder default False; property LockUpdateCount: integer read fLockUpdateCount; property SelectedGrip: integer read fSelGrip write fSelGrip; property Font: TFont read fFont; end; {!! TIEViewRulerParams Description Specifies the properties of embedded rulers within a TImageEnView (if
is not []). Example // Show rulers in TImageEnView ImageEnView1.ShowRulers := [ rdHorizontal, rdVertical ]; // Set units to CM ImageEnView1.RulerParams.Units := ieruCentimeters; // Show grips as a line ImageEnView1.RulerParams.Units := gkLine; Methods and Properties Display Grip Properties Other Events !!} TIEViewRulerParams = class private { Private declarations } fOwner: TControl; fHorzRuler: TIERuler; fVertRuler: TIERuler; fSnapGrips: TIERulerSnapping; fConstrainGrips: Boolean; fAlignToImage: Boolean; fUnits: TIERulerUnits; fWasUnits: TIERulerUnits; fHorzPos: TGripsDir; fVertPos: TGripsXDir; fHorzHeight : Integer; fVertWidth : Integer; fGripsPosBase: TIERulerPosBase; // Limit duplicate paints caused by the MouseMove handling fLastMouseMoveX : Integer; fLastMouseMoveY : Integer; fLastMouseMoveShift : TShiftState; fLastMouseMoveResult: Boolean; function GetHorzGripsPos(i: integer): double; procedure SetHorzGripsPos(i: integer; p: double); function GetHorzGripsColor(i: integer): TColor; procedure SetHorzGripsColor(i: integer; p: TColor); function GetHorzGripsMin(i: integer): double; procedure SetHorzGripsMin(i: integer; v: double); function GetHorzGripsMax(i: integer): double; procedure SetHorzGripsMax(i: integer; v: double); function GetVertGripsPos(i: integer): double; procedure SetVertGripsPos(i: integer; p: double); function GetVertGripsColor(i: integer): TColor; procedure SetVertGripsColor(i: integer; p: TColor); function GetVertGripsMin(i: integer): double; procedure SetVertGripsMin(i: integer; v: double); function GetVertGripsMax(i: integer): double; procedure SetVertGripsMax(i: integer; v: double); function GetMinLabelSpacing: integer; procedure SetMinLabelSpacing(v: integer); function GetFrequency: double; procedure SetFrequency(v: double); function GetLabelFrequency: double; procedure SetLabelFrequency(v: double); function GetShowMeasure: boolean; procedure SetShowMeasure(v: boolean); function GetMeasureColor: TColor; procedure SetMeasureColor(v: TColor); function GetColor: TColor; procedure SetColor(c: TColor); function GetHorzInverted: boolean; procedure SetHorzInverted(v: boolean); function GetVertInverted: boolean; procedure SetVertInverted(v: boolean); function GetLabelPrecision: integer; procedure SetLabelPrecision(v: integer); function GetScrollRate: double; procedure SetScrollRate(const Value: double); function GetCursorGripKind: TGripKind; procedure SetCursorGripKind(const Value: TGripKind); function GetGripKindDefault: TGripKind; procedure SetGripKindDefault(const Value: TGripKind); function GetGripColorDefault: TColor; procedure SetGripColorDefault(const Value: TColor); function GetGripPenColor: TColor; procedure SetGripPenColor(const Value: TColor); function GetHorzGripsCount: integer; procedure SetHorzGripsCount(v: integer); function GetHorzGripsKind(i: integer): TGripKind; procedure SetHorzGripsKind(i: integer; v: TGripKind); function GetVertGripsCount: integer; procedure SetVertGripsCount(v: integer); function GetVertGripsKind(i: integer): TGripKind; procedure SetVertGripsKind(i: integer; v: TGripKind); function GetGripWidth: integer; procedure SetGripWidth(v: integer); function GetGripHeight: integer; procedure SetGripHeight(const Value: integer); function GetFont: TFont; procedure FontChange(Sender: TObject); procedure SetSnapGrips(Value: TIERulerSnapping); procedure SetConstrainGrips(Value: Boolean); procedure SetAlignToImage(Value: Boolean); procedure SetUnits(Value: TIERulerUnits); procedure SetHorzPos(Value: TGripsDir); procedure SetVertPos(Value: TGripsXDir); procedure SetVertWidth(Value: Integer); procedure SetHorzHeight(Value: Integer); function GetHorzRulerRect: TRect; function GetVertRulerRect: TRect; procedure MouseMoveOutsideRuler(Shift: TShiftState; X, Y: Integer); procedure ConstrainGripsCB(Sender: TObject; var GripPos: double); procedure CheckGripBounds(); function ImageLeftOnHorzRuler(): double; function ImageRightOnHorzRuler(): double; function ImageTopOnVertRuler(): double; function ImageBottomOnVertRuler(): double; function ApplyHorzConstraints(value : double; DoSnapGrips : TIERulerSnapping = iesnNone; DoConstrainGrips : Boolean = False) : double; function ApplyVertConstraints(value : double; DoSnapGrips : TIERulerSnapping = iesnNone; DoConstrainGrips : Boolean = False) : double; function ScrToRulerX(X : Integer) : double; function RulerToScrX(Pos : Double) : Integer; function ScrToRulerY(Y : Integer) : double; function RulerToScrY(Pos : Double) : Integer; function ValueToRulerX(Value : double; ValueBase: TIERulerPosBase) : double; function RulerToValueX(Pos : double; ValueBase: TIERulerPosBase) : double; function ValueToRulerY(Value : double; ValueBase: TIERulerPosBase) : double; function RulerToValueY(Pos : Double; ValueBase: TIERulerPosBase) : Double; function HorzRulerVisible: Boolean; function VertRulerVisible: Boolean; procedure LockUpdate(); procedure UnlockUpdate(DoUpdate: Boolean = True; DoInvalidate: Boolean = True); function GetOnRulerClick: TRulerClickEvent; function GetOnRulerGripClick: TRulerGripClickEvent; function GetOnRulerGripDblClick: TRulerGripClickEvent; function GetOnRulerPosChange: TRulerGripPosChangeEvent; procedure SetOnRulerClick(const Value: TRulerClickEvent); procedure SetOnRulerGripClick(const Value: TRulerGripClickEvent); procedure SetOnRulerGripDblClick(const Value: TRulerGripClickEvent); procedure SetOnRulerPosChange(const Value: TRulerGripPosChangeEvent); function GetShowBorder: boolean; procedure SetShowBorder(const Value: boolean); protected { Protected declarations } public { Public declarations } constructor Create(Owner: TControl); destructor Destroy; override; property HorzGripsPos[g: integer]: double read GetHorzGripsPos write SetHorzGripsPos; property HorzGripsColor[g: integer]: TColor read GetHorzGripsColor write SetHorzGripsColor; property HorzGripsKind[g: integer]: TGripKind read GetHorzGripsKind write SetHorzGripsKind; property HorzGripsMin[g: integer]: double read GetHorzGripsMin write SetHorzGripsMin; property HorzGripsMax[g: integer]: double read GetHorzGripsMax write SetHorzGripsMax; property VertGripsPos[g: integer]: double read GetVertGripsPos write SetVertGripsPos; property VertGripsColor[g: integer]: TColor read GetVertGripsColor write SetVertGripsColor; property VertGripsKind[g: integer]: TGripKind read GetVertGripsKind write SetVertGripsKind; property VertGripsMin[g: integer]: double read GetVertGripsMin write SetVertGripsMin; property VertGripsMax[g: integer]: double read GetVertGripsMax write SetVertGripsMax; property ScrollRate: double read GetScrollRate write SetScrollRate; property Color: TColor read GetColor write SetColor default clBtnFace; property GripPenColor : TColor read GetGripPenColor write SetGripPenColor default clWindowFrame; property GripWidth: integer read GetGripWidth write SetGripWidth default 12; property GripHeight: integer read GetGripHeight write SetGripHeight; property ShowMeasure: boolean read GetShowMeasure write SetShowMeasure default true; property Frequency: double read GetFrequency write SetFrequency; property LabelFrequency: double read GetLabelFrequency write SetLabelFrequency; property MeasureColor: TColor read GetMeasureColor write SetMeasureColor default clBtnFace; property LabelPrecision: integer read GetLabelPrecision write SetLabelPrecision default 3; property MinLabelSpacing: integer read GetMinLabelSpacing write SetMinLabelSpacing default 30; property CursorGripKind: TGripKind read GetCursorGripKind write SetCursorGripKind default gkLine; property GripKindDefault: TGripKind read GetGripKindDefault write SetGripKindDefault default gkTriangle; property GripColorDefault: TColor read GetGripColorDefault write SetGripColorDefault default cl3DLight; property HorzGripsCount: integer read GetHorzGripsCount write SetHorzGripsCount default 1; property VertGripsCount: integer read GetVertGripsCount write SetVertGripsCount default 1; property HorzPos: TGripsDir read fHorzPos write SetHorzPos default gdUp; property VertPos: TGripsXDir read fVertPos write SetVertPos default gdLeft; property HorzInverted: boolean read GetHorzInverted write SetHorzInverted default false; property VertInverted: boolean read GetVertInverted write SetVertInverted default false; property ShowBorder : boolean read GetShowBorder write SetShowBorder default True; {!! TIEViewRulerParams.GripsPosBase Declaration property GripsPosBase: ; Description Specifies the type of values used for grip position properties: , , , , and . The following options are available: Item Description ierbRuler Values are ruler values (taking into account the DPI set by ierbBitmap Values are pixel positions on the currently displayed image (regardless of zoom, scrolling, etc) ierbScreen Values are screen values
Default: ierbBitmap Example // Add three grips at 25%, 50% and 75% of the image width ImageEnView1.RulerParams.HorzGripsCount := 3; ImageEnView1.RulerParams.GripsPosBase := ierbBitmap; // Units are relative to the bitmap ImageEnView1.RulerParams.HorzGripsPos[ 0 ] := MulDiv( ImageEnView1.IEBitmap.Width, 1, 4 ); ImageEnView1.RulerParams.HorzGripsPos[ 1 ] := MulDiv( ImageEnView1.IEBitmap.Width, 2, 4 ); ImageEnView1.RulerParams.HorzGripsPos[ 2 ] := MulDiv( ImageEnView1.IEBitmap.Width, 3, 4 ); !!} property GripsPosBase: TIERulerPosBase read fGripsPosBase write fGripsPosBase; property Font: TFont read GetFont; property SnapGrips: TIERulerSnapping read fSnapGrips write SetSnapGrips default iesnNone; property ConstrainGrips: Boolean read fConstrainGrips write SetConstrainGrips default True; property AlignToImage: Boolean read fAlignToImage write SetAlignToImage default False; property Units: TIERulerUnits read fUnits write SetUnits default ieruPixels; property HorzHeight: Integer read fHorzHeight write SetHorzHeight default 40; property VertWidth: Integer read fVertWidth write SetVertWidth default 40; // EVENTS property OnRulerGripPosChange: TRulerGripPosChangeEvent read GetOnRulerPosChange write SetOnRulerPosChange; property OnRulerGripClick: TRulerGripClickEvent read GetOnRulerGripClick write SetOnRulerGripClick; property OnRulerGripDblClick: TRulerGripClickEvent read GetOnRulerGripDblClick write SetOnRulerGripDblClick; property OnRulerClick: TRulerClickEvent read GetOnRulerClick write SetOnRulerClick; // Need to handle the following in objects that use this class procedure Update(DoInvalidate: Boolean = True); procedure Paint(Canvas: TCanvas); function HandleMouseMove(Shift: TShiftState; X, Y: Integer): Boolean; procedure HandleMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HandleMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure HandleSpecialKey(CharCode: Word; Shift: TShiftState); // Internal Helper properties property HorzRulerRect: TRect read GetHorzRulerRect; property VertRulerRect: TRect read GetVertRulerRect; function RulerAreaLeft: Integer; function RulerAreaRight: Integer; function RulerAreaTop: Integer; function RulerAreaBottom: Integer; procedure ScrollToHorzGrip(g: Integer); procedure ScrollToVertGrip(g: Integer); end; implementation uses iexThemes, imageenproc, hyieutils, hyiedefs, imageenview, RulerBox, Forms; {$R-} type TRUGrip = record Pos: double; // position Color: TColor; // color Kind: TGripKind; // type Min: double; // min position Max: double; // max position Default: Boolean; // If false, then a custom color and kind have been set end; PRUGrip = ^TRUGrip; const // Number of points for each grip type NumLinesGKind: array[gkTriangle..gkLine] of integer = ( 3, // gkTriangle 3, // gkLeftTriangle 3, // gkRightTriangle 7, // gkArrow 5, // gkArrow2 2 // gkLine ); Ruler_To_Text_Spacing = 3; // Distance between ruler and labels NON_VIZ = -10000; // Grip is not shown ///////////////////////////////////////////////////////////////////////////////////////// // // // TIERULER // // // ///////////////////////////////////////////////////////////////////////////////////////// constructor TIERuler.Create(Owner: TControl); begin inherited Create(); fOwner := Owner; IEGDIPLoadLibrary(); fFont := TFont.Create; fGripIndexOffset := 0; if fOwner is TImageEnVIew then fGripIndexOffset := 1 else if fOwner is TRulerBox then fFont.Assign( TRulerBox( fOwner ).Font ); fFont.OnChange := FontChange; fLockUpdateCount := 0; fRulerDir := rdHorizontal; fOffsetX := 0; fOffsetY := 0; fInverted := false; fHexLabels := false; fGripsDir := gdUp; fBackground := clBtnFace; fGripBaseDim := 12; fShowRuler := true; fViewPos := 0; fDPU := 1; fFrequency := 10; fLabelFreq := 40; fRulerColor := clBtnFace; fViewMin := 0; fViewMax := 0; fMaxGripHeight := 15; fOnRulerGripPosChange := nil; fOnRulerGripClick := nil; fOnRulerGripDblClick := nil; fOnRulerClick := nil; fFitInView := false; fBitmap := TBitmap.create; fBitmap.PixelFormat := pf24bit; fBitmap.Width := fOwner.Width - fOffsetX; fBitmap.Height := fOwner.Height - fOffsetY; fGrips := TList.Create; fSelGrip := -1; fScrollRate := 1.0; fLabelPrecision := 3; fMinLabelSpacing := 30; fGripPenColor := clWindowFrame; fGripKindDefault := gkTriangle; fGripColorDefault := clBtnFace; SetGripsCount(1); Update(); end; destructor TIERuler.Destroy; var i: integer; begin FreeAndNil( fBitmap ); FreeAndNil( fFont ); for i := 0 to fGrips.Count-1 do dispose(fGrips[i]); FreeAndNil(fGrips); IEGDIPUnLoadLibrary(); inherited; end; procedure TIERuler.DrawToCanvas(Canvas: TCanvas; X, Y: Integer); begin Canvas.Draw( X + fOffsetX, Y + fOffsetY, fBitmap); end; procedure TIERuler.UpdateSize(Width, Height: integer); begin fBitmap.Width := imax( 0, Width - fOffsetX ); fBitmap.Height := imax( 0, Height - fOffsetY ); Update(); end; procedure TIERuler.SetBackground(bk: TColor); begin fBackground := bk; Update(); end; function TIERuler.GetGripsCount: integer; begin result := fGrips.Count; end; procedure TIERuler.SetGripsCount(v: integer); var ex, q: integer; begin ex := fGrips.Count; if v <> ex then begin if v < ex then // free for q := ex-1 downto v do dispose(fGrips[q]); fGrips.Count := v; // init for q := ex to v - 1 do begin fGrips[q] := new(PRUGrip); // defaults PRUGrip(fGrips[q])^.Pos := 0; PRUGrip(fGrips[q])^.Color := GetThemeColor( ietpRulerGripFill, fGripColorDefault ); PRUGrip(fGrips[q])^.Kind := fGripKindDefault; PRUGrip(fGrips[q])^.Min := fViewMin; PRUGrip(fGrips[q])^.Max := fViewMax; PRUGrip(fGrips[q])^.Default := True; end; Update(); end; end; procedure TIERuler.SetGripPenColor(const Value: TColor); begin fGripPenColor := Value; Update(); end; function TIERuler.GetGripsPos(i: integer): double; begin if i < fGrips.Count then result := PRUGrip(fGrips[i])^.Pos else result := 0; end; procedure TIERuler.SetGripsPos(i: integer; p: double); begin if i < fGrips.Count then begin PRUGrip(fGrips[i])^.Pos := p; AdjustGripLimits(i); if assigned( fOnRulerGripPosChange ) and ( i >= fGripIndexOffset ) then fOnRulerGripPosChange( self, fRulerDir, i - fGripIndexOffset, PRUGrip(fGrips[i])^.Pos ); UpdateEx( False, True ); end; end; function TIERuler.GetGripsColor(i: integer): TColor; begin if i < fGrips.Count then result := PRUGrip(fGrips[i])^.Color else result := 0; end; procedure TIERuler.SetGripsColor(i: integer; p: TColor); begin if i < fGrips.Count then begin PRUGrip(fGrips[i])^.Color := p; PRUGrip(fGrips[i])^.Default := False; Update(); end; end; procedure TIERuler.SetGripColorDefault(const Value: TColor); var i: Integer; begin fGripColorDefault := Value; for i := 0 to fGrips.Count - 1 do if PRUGrip( fGrips[ i ])^.Default then PRUGrip( fGrips[ i ])^.Color := Value; Update(); end; procedure TIERuler.SetGripBaseDim(v: integer); begin fGripBaseDim := v; Update(); end; function TIERuler.GetGripsKind(i: integer): TGripKind; begin result := gkTriangle; // default if i < fGrips.Count then result := PRUGrip(fGrips[i])^.Kind; end; procedure TIERuler.SetGripsKind(i: integer; v: TGripKind); begin if i < fGrips.Count then begin PRUGrip(fGrips[i])^.Kind := v; PRUGrip(fGrips[i])^.Default := False; Update(); end; end; procedure TIERuler.SetGripKindDefault(const Value: TGripKind); var i: Integer; begin fGripKindDefault := Value; for i := 0 to fGrips.Count - 1 do if PRUGrip( fGrips[ i ])^.Default then PRUGrip( fGrips[ i ])^.Kind := Value; Update(); end; // return -1 = none function TIERuler.GetClickedGrip(x, y: integer): integer; var q: integer; rc: TRect; begin result := -1; for q := fGrips.Count - 1 downto 0 do begin GetGripRect(q, rc); if PtInRect(rc, Point(x, y)) then begin result := q; break; end; end; end; // returns the rectangle where the grip "gn" is contained. // Right and bottom borders are incremented by 1 to make them compatible with PtInRect. procedure TIERuler.GetGripRect(gn: integer; var rc: TRect); var poly: TIEPolyg; q: integer; begin if GripsKind[ gn ] = gkNone then begin rc := Rect( 0, 0, -1, -1 ); exit; end; GetGripPoly(gn, poly); rc.TopLeft := poly[0]; rc.BottomRight := poly[0]; for q := 1 to NumLinesGKind[GripsKind[gn]] - 1 do begin if poly[q].X < rc.Left then rc.Left := poly[q].X; if poly[q].X > rc.Right then rc.Right := poly[q].X; if poly[q].Y < rc.Top then rc.Top := poly[q].Y; if poly[q].Y > rc.Bottom then rc.Bottom := poly[q].Y; end; inc(rc.Bottom); inc(rc.Right); end; procedure TIERuler.SetGripsDir(v: TGripsDir); begin fGripsDir := v; Update(); end; procedure TIERuler.SetShowBorder(const Value: boolean); begin fShowBorder := Value; Update(); end; procedure TIERuler.SetShowRuler(v: boolean); begin fShowRuler := v; Update(); end; // return height of ruler+text function TIERuler.GetRulerHeight: integer; const Min_Tick_Size = 3; Min_Grip_Height = 3; var minHeight, availHeight: Integer; begin result := 0; if fShowRuler = False then exit; // New method if fOwner is TImageEnView then begin if fRulerDir = rdHorizontal then availHeight := fBitmap.Height else availHeight := fBitmap.Width; minHeight := abs( fFont.Height ) + Ruler_To_Text_Spacing + Min_Tick_Size; result := availHeight - fMaxGripHeight; if result < minHeight then result := minHeight; if Result + Min_Grip_Height > availHeight then Result := availHeight - Min_Grip_Height; end else begin // Legacy method (TRulerBox) if fRulerDir = rdHorizontal then result := trunc( abs( fFont.Height ) * 1.5 ) + Ruler_To_Text_Spacing else result := fBitmap.Width - fMaxGripHeight; end; end; procedure TIERuler.Update(); begin UpdateEx( True, True ); end; procedure TIERuler.UpdateEx(RepaintAll, DoInvalidate : Boolean); begin if fLockUpdateCount > 0 then exit else if ( fOwner is TImageEnView ) and ( TImageEnView( fOwner ).LockUpdateCount > 0 ) then exit else if ( fOwner is TImageEnView ) and (( fRulerDir in TImageEnView( fOwner ).ShowRulers ) = False ) then exit; if fFitinView then begin if (fViewMax - fViewMin <> 0) then fDPU := (fBitmap.Width) / (fViewMax - fViewMin); AdjustViewLimits; RepaintAll := True; end; RepaintGrips; if RepaintAll then RepaintRuler; if fShowBorder then RepaintBorder; if DoInvalidate then fOwner.invalidate; end; procedure TIERuler.SetViewPos(v: double); begin fViewPos := v; AdjustViewLimits; Update(); end; procedure TIERuler.SetFrequency(v: double); begin fFrequency := v; Update(); end; procedure TIERuler.SetLabelFreq(v: double); begin fLabelFreq := v; Update(); end; // returns X position (in pixels) of grip "gn" function TIERuler.GetXGripPos(gn: integer): integer; begin result := round(fDPU * (GripsPos[gn] - fViewPos)); if fInverted then begin if fRulerDir = rdHorizontal then result := fBitmap.Width - result else result := fBitmap.Height - result; end; end; procedure TIERuler.SetRulerColor(v: TColor); begin fRulerColor := v; Update(); end; procedure TIERuler.SetRulerDir(v: TRulerDir); begin fRulerDir := v; Update(); end; // returns coordinates of points making the grip procedure TIERuler.GetGripPoly(gn: integer; var poly: TIEPolyg); var w, h, b: integer; borderSize: integer; begin borderSize := 0; if fShowBorder and ( GripsKind[gn] <> gkLine ) then borderSize := 1; b := 0; h := 0; if csDesigning in fOwner.ComponentState then w := (fGripBaseDim + 5) * gn else w := GetXGripPos(gn); if fGripsDir = gdUp then begin if fRulerDir = rdHorizontal then begin h := fBitmap.Height - 2 - borderSize; b := 0; end else begin h := fBitmap.Width - 2 - borderSize; b := 0; end; if fShowRuler then inc(b, GetRulerHeight); end else if fGripsDir = gdDown then begin if fRulerDir = rdHorizontal then begin b := fBitmap.Height - 1; h := 1 + borderSize; end else begin b := fBitmap.Width - 1; h := 1 + borderSize; end; if fShowRuler then dec(b, GetRulerHeight); end; case GripsKind[gn] of gkTriangle: begin poly[0].x := w - (fGripBaseDim div 2); poly[0].y := h; poly[1].x := w + (fGripBaseDim div 2); poly[1].y := h; poly[2].x := w; poly[2].y := b; end; gkLeftTriangle: begin poly[0].x := w - (fGripBaseDim div 2); poly[0].y := h; poly[1].x := w; poly[1].y := h; poly[2].x := w; poly[2].y := b; end; gkRightTriangle: begin poly[0].x := w; poly[0].y := h; poly[1].x := w + (fGripBaseDim div 2); poly[1].y := h; poly[2].x := w; poly[2].y := b; end; gkArrow: begin poly[0].x := w - (fGripBaseDim div 4); poly[0].y := h; poly[1].x := w + (fGripBaseDim div 4); poly[1].y := poly[0].y; poly[2].x := poly[1].x; if fGripsDir = gdUp then poly[2].y := b + ((h - b) div 2) else poly[2].y := h + ((b - h) div 2); poly[3].x := w + (fGripBaseDim div 2); poly[3].y := poly[2].y; poly[4].x := w; poly[4].y := b; poly[5].x := w - (fGripBaseDim div 2); poly[5].y := poly[2].y; poly[6].x := poly[0].x; poly[6].y := poly[2].y; end; gkArrow2: begin poly[0].x := w - (fGripBaseDim div 2); poly[0].y := h; poly[1].x := w + (fGripBaseDim div 2); poly[1].y := poly[0].y; poly[2].x := poly[1].x; if fGripsDir = gdUp then poly[2].y := b + (h - b) div 2 else poly[2].y := h + (b - h) div 2; poly[3].x := w; poly[3].y := b; poly[4].x := poly[0].x; poly[4].y := poly[2].y; end; gkLine: begin poly[0].x := w; poly[0].y := h; poly[1].x := w; poly[1].y := b; end; end; if fRulerDir = rdVertical then for w := 0 to NumLinesGKind[GripsKind[gn]] - 1 do iswap(poly[w].x, poly[w].y); end; procedure TIERuler.RepaintGrips; var q, rh: integer; poly: TIEPolyg; iec: TIECanvas; begin iec := TIECanvas.Create( fBitmap.Canvas, true, true); iec.Brush.Color := GetThemeColor( ietpRulerBackground, fBackground ); rh := GetRulerHeight; if fRulerDir = rdHorizontal then begin if fGripsDir = gdUp then iec.Fillrect(rect(0, rh, fBitmap.Width, fBitmap.Height)) else if fgripsDir = gdDown then iec.FillRect(rect(0, 0, fBitmap.Width, fBitmap.Height - rh)); end else begin if fGripsDir = gdUp then iec.FillRect(rect(rh, 0, fBitmap.Width, fBitmap.Height)) else if fgripsDir = gdDown then iec.FillRect(rect(0, 0, fBitmap.Width - rh, fBitmap.Height)); end; for q := 0 to fGrips.Count - 1 do if ( GripsKind[ q ] <> gkNone ) and ( GripsPos[ q ] <> NON_VIZ ) then begin GetGripPoly(q, poly); // paint grip iec.Brush.Color := GripsColor[q]; iec.Pen.Color := GetThemeColor( ietpRulerGripBorder, fGripPenColor ); iec.Polygon(slice(poly, NumLinesGKind[GripsKind[q]])); end; iec.Free; end; // adjusts limits of specified grip (looking at Max and Min) procedure TIERuler.AdjustGripLimits(gn: integer); begin if GripsMin[gn] < GripsMax[gn] then begin if GripsPos[gn] < GripsMin[gn] then GripsPos[gn] := GripsMin[gn] else if GripsPos[gn] > GripsMax[gn] then GripsPos[gn] := GripsMax[gn]; end; end; // adjusts limits of fViewPos (looking at fViewMin and fViewMax) procedure TIERuler.AdjustViewLimits; var wiu: Double; begin if ( fViewMin < fViewMax ) and ( fBitmap.Width > 0 ) then begin // return horizontal size in Units wiu := fBitmap.Width / fDPU; if fViewPos < fViewMin then fViewPos := fViewMin else if fViewPos > (fViewMax - wiu) then fViewpos := dmax(0, fViewMax - wiu); end; end; procedure TIERuler.HandleMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; {$IFDEF IEDEBUG} OutputDebugStringA( 'Mouse Down' ); {$ENDIF} dec(X, fOffsetX); dec(Y, fOffsetY); if (Button = mbLeft) then begin fSelGrip := GetClickedGrip(x, y); fMX1 := X; fMY1 := Y; if fSelGrip >= 0 then begin if (ssDouble in Shift) and assigned(fOnRulerGripDblClick) and ( fSelGrip >= fGripIndexOffset ) then fOnRulerGripDblClick( fOwner, fRulerDir, fSelGrip - fGripIndexOffset, PRUGrip( fGrips[ fSelGrip ])^.Pos ); fSelGripSt := GetXGripPos( fSelGrip ); end else begin if assigned(fOnRulerClick) then fOnRulerClick( fOwner, fRulerDir, X / fDPU + fViewPos); end; end; end; procedure TIERuler.HandleMouseMove(Shift: TShiftState; X, Y: Integer); begin HandleMouseMoveEx( Shift, X, Y, nil ); end; procedure TIERuler.HandleMouseMoveEx(Shift: TShiftState; X, Y: Integer; SetGripCallBack: TRulerSetGripPosEvent); {} procedure _DoScroll_IEView(Dir: Integer); begin case Dir of VK_LEFT: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt - fMX1 ) / fDPU + fViewPos - (fScrollRate / fDPU); TImageEnView(fOwner).ViewX := Round( TImageEnView(fOwner).ViewX - (fScrollRate / fDPU)); end; VK_RIGHT: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt + fBitmap.Width - 1 - fMX1 ) / fDPU + fViewPos + (fScrollRate / fDPU); TImageEnView(fOwner).ViewX := Round( TImageEnView(fOwner).ViewX + (fScrollRate / fDPU)); end; VK_UP: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt - fMY1 ) / fDPU + fViewPos - (fScrollRate / fDPU); if fOwner is TImageEnView then TImageEnView(fOwner).ViewY := Round( TImageEnView(fOwner).ViewY - (fScrollRate / fDPU)); end; VK_DOWN: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt + fBitmap.Height- 1 - fMY1 ) / fDPU + fViewPos + (fScrollRate / fDPU); TImageEnView(fOwner).ViewY := Round( TImageEnView(fOwner).ViewY + (fScrollRate / fDPU)); end; end; AdjustGripLimits( fSelGrip ); AdjustViewLimits; if assigned(fOnRulerGripPosChange) and ( fSelGrip >= fGripIndexOffset ) then fOnRulerGripPosChange( fOwner, fRulerDir, fSelGrip - fGripIndexOffset, PRUGrip( fGrips[ fSelGrip ])^.Pos ); end; {} function _DoScroll_RB(Dir: Integer): integer; var p: TPoint; begin GetCursorPos(p); p := fOwner.ScreenToClient(p); case Dir of VK_LEFT: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt - fMX1 ) / fDPU + fViewPos - (fScrollRate / fDPU); fViewPos := fViewPos - (fScrollRate / fDPU); end; VK_RIGHT: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt + fBitmap.Width - 1 - fMX1 ) / fDPU + fViewPos + (fScrollRate / fDPU); fViewPos := fViewPos + (fScrollRate / fDPU); end; VK_UP: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt - fMY1 ) / fDPU + fViewPos - (fScrollRate / fDPU); fViewPos := fViewPos - (fScrollRate / fDPU); end; VK_DOWN: begin PRUGrip(fGrips[ fSelGrip ])^.Pos := ( fSelGripSt + fBitmap.Height- 1 - fMY1 ) / fDPU + fViewPos + (fScrollRate / fDPU); fViewPos := fViewPos + (fScrollRate / fDPU); end; end; AdjustGripLimits( fSelGrip ); AdjustViewLimits; RepaintGrips; RepaintRuler; fOwner.Invalidate(); if assigned(fOnRulerGripPosChange) and ( fSelGrip >= fGripIndexOffset ) then fOnRulerGripPosChange( fOwner, fRulerDir, fSelGrip - fGripIndexOffset, PRUGrip( fGrips[ fSelGrip ])^.Pos ); if Dir in [ VK_LEFT, VK_RIGHT ] then result := p.X else result := p.Y; end; {} function _CheckConstraints(v: Double) : Double; begin Result := v; if assigned( SetGripCallBack ) then SetGripCallBack( Self, Result ); end; {} function _CheckInverted(Dir: Integer) : Integer; begin Result := Dir; if fInverted then case Dir of VK_LEFT : Result := VK_RIGHT; VK_RIGHT : Result := VK_LEFT ; VK_UP : Result := VK_DOWN ; VK_DOWN : Result := VK_UP ; end; end; {} var isMouseCapture: Boolean; begin inherited; // dec(X, fOffsetX); dec(Y, fOffsetY); isMouseCapture := False; if fOwner is TRulerBox then isMouseCapture := TRulerBox( fOwner ).MouseCapture else if fOwner is TImageEnView then isMouseCapture := TImageEnView( fOwner ).MouseCapture; if isMouseCapture then if (fSelGrip >= 0) then begin if fRulerDir = rdHorizontal then begin if X < 0 then begin // Scroll Left if fOwner is TImageEnView then _DoScroll_IEView( _CheckInverted( VK_LEFT )) else while ( _DoScroll_RB( _CheckInverted( VK_LEFT )) < 0) and (GetAsyncKeyState(VK_LBUTTON) <> 0) do Application.ProcessMessages end else if X >= fBitmap.Width then begin // Scroll Right if fOwner is TImageEnView then _DoScroll_IEView( _CheckInverted( VK_RIGHT )) else while ( _DoScroll_RB( _CheckInverted( VK_RIGHT )) >= fBitmap.Width) and (GetAsyncKeyState(VK_LBUTTON) <> 0) do Application.ProcessMessages end else begin // Move Horz Grip if fInverted then SetGripsPos( fSelGrip, _CheckConstraints(( fSelGripSt + (fBitmap.Width-X) - fMX1) / fDPU + fViewPos )) else SetGripsPos( fSelGrip, _CheckConstraints(( fSelGripSt + X - fMX1) / fDPU + fViewPos )); fOwner.Invalidate(); end; end else begin if Y < 0 then begin // Scroll Up if fOwner is TImageEnView then _DoScroll_IEView( _CheckInverted( VK_UP )) else while ( _DoScroll_RB( _CheckInverted( VK_UP )) < 0) and (GetAsyncKeyState(VK_LBUTTON) <> 0) do Application.ProcessMessages end else if Y >= fBitmap.Height then begin // Scroll Down if fOwner is TImageEnView then _DoScroll_IEView( _CheckInverted( VK_DOWN )) else while ( _DoScroll_RB( _CheckInverted( VK_DOWN )) >= fBitmap.height) and (GetAsyncKeyState(VK_LBUTTON) <> 0) do Application.ProcessMessages end else begin // Move Vert Grip if fInverted then SetGripsPos( fSelGrip, _CheckConstraints(( fSelGripSt + (fBitmap.Height-Y) - fMY1) / fDPU + fViewPos )) else SetGripsPos( fSelGrip, _CheckConstraints(( fSelGripSt + Y - fMY1) / fDPU + fViewPos )); fOwner.Invalidate(); end; end end; end; // fMouseSel 0=none 1=capture on sat/val 2=capture on hue procedure TIERuler.HandleMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin {$IFDEF IEDEBUG} OutputDebugStringA( 'Mouse Up' ); {$ENDIF} dec(X, fOffsetX); dec(Y, fOffsetY); if fSelGrip >= 0 then begin if (fMX1 = X) and (fMY1 = Y) and assigned(fOnRulerGripClick) and ( fSelGrip >= fGripIndexOffset ) then fOnRulerGripClick( fOwner, fRulerDir, fSelGrip - fGripIndexOffset, PRUGrip( fGrips[ fSelGrip ])^.Pos ); end; end; function TIERuler.GetGripsMax(i: integer): double; begin if i < fGrips.Count then result := PRUGrip(fGrips[i])^.Max else result := 0; end; procedure TIERuler.SetGripsMax(i: integer; v: double); var q: integer; begin if (i < fGrips.Count) then begin PRUGrip(fGrips[i])^.Max := v; for q := 0 to fGrips.Count - 1 do AdjustGripLimits(q); Update(); end; end; function TIERuler.GetGripsMin(i: integer): double; begin if i < fGrips.Count then result := PRUGrip(fGrips[i])^.Min else result := 0; end; procedure TIERuler.SetGripsMin(i: integer; v: double); var q: integer; begin if (i < fGrips.Count) then begin PRUGrip(fGrips[i])^.Min := v; for q := 0 to fGrips.Count - 1 do AdjustGripLimits(q); Update(); end; end; procedure TIERuler.SetViewMin(v: double); var q: integer; begin fViewMin := v; AdjustViewLimits; for q := 0 to fGrips.Count - 1 do PRUGrip(fGrips[q])^.Min := fViewMin; Update(); end; procedure TIERuler.SetViewMax(v: double); var q: integer; begin fViewMax := v; AdjustViewLimits; for q := 0 to fGrips.Count - 1 do PRUGrip(fGrips[q])^.Max := fViewMax; Update(); end; procedure TIERuler.RepaintBorder; {} procedure _DrawBorder(x1, y1, x2, y2 : Integer); begin fBitmap.Canvas.MoveTo( x1, y1 ); fBitmap.Canvas.LineTo( x2, y2 ); end; {} begin fBitmap.Canvas.Pen.Color := GetThemeColor( ietpRulerBorder, clBtnShadow ); if fRulerDir = rdHorizontal then begin if fGripsDir = gdDown then _DrawBorder( 0, 0, fBitmap.Width, 0 ) else _DrawBorder( 0, fBitmap.Height - 1, fBitmap.Width, fBitmap.Height - 1 ); end else begin if fGripsDir = gdDown then _DrawBorder( 0, 0, 0, fBitmap.Height ) else _DrawBorder( fBitmap.Width - 1, 0, fBitmap.Width - 1, fBitmap.Height ); end; end; // repaint ruler+text procedure TIERuler.RepaintRuler; var LogFont: TLogFontA; SaveFont: TFont; rl: integer; // ruler height bigTickFreq : Double; // Local value of fLabelFreq littleTickFreq: Double; // Local value of fFrequency bigTickSpacing: Integer; // Pixels between big ticks fontColor: TColor; {} function _FloatToLabel(v: double) : string; var lb1: string; e: integer; begin if fHexLabels then begin lb1 := IntToHex(trunc(abs( v )), 6); // remove starting zeros Result := '0'; for e := 1 to length(lb1) do if lb1[e] <> '0' then begin Result := Copy(lb1, e, length(lb1)); break; end; if v < 0 then Result := '-' + Result; end else Result := IEFloatToFormatString( v, fLabelPrecision, True ); end; {} procedure _DrawHorzTicks(TickFrequency: Double; TickScale: Integer; DrawLabel: Boolean); var q, w: integer; z, v: double; // pos in unit x: integer; // pos in pixel xx: integer; // Draw pos lb: string; begin w := trunc((fBitmap.Width / fDPU) / TickFrequency); // number of lines for q := 0 to w + 1 do begin v := ((fViewPos / TickFrequency) - trunc(fViewPos / TickFrequency)) * TickFrequency; z := q * TickFrequency + fViewPos - v; x := round((z - fViewPos) * fDPU); if fInverted then x := fBitmap.Width - x; if fGripsDir = gdDown then begin // DOWN fBitmap.Canvas.MoveTo( x, fBitmap.Height - rl ); fBitmap.Canvas.LineTo( x, fBitmap.Height - rl + ( rl div TickScale ) - 1 ); end else begin // UP fBitmap.Canvas.MoveTo( x, rl - 1 ); fBitmap.Canvas.LineTo( x, rl - ( rl div TickScale ) + 1 ); end; if DrawLabel then begin lb := _FloatToLabel( z ); xx := x - (fBitmap.Canvas.TextWidth(lb) div 2); if xx <= 0 then begin { Don't draw half a zero } end else if fGripsDir = gdDown then fBitmap.Canvas.TextOut(xx, fBitmap.Height - fBitmap.Canvas.TextHeight( lb ), lb) else fBitmap.Canvas.TextOut(xx, 0, lb); end; end; end; {} procedure _DrawVertTicks(TickFrequency: Double; TickScale: Integer; DrawLabel: Boolean); var w, q: Integer; z, v: double; // pos in unit y: integer; // pos in pixel yy: integer; // Draw pos lb: string; tw: Integer; begin w := trunc((fBitmap.Height / fDPU) / TickFrequency); // number of rows for q := 0 to w + 1 do begin v := ((fViewPos / TickFrequency) - trunc(fViewPos / TickFrequency)) * TickFrequency; z := q * TickFrequency + fViewPos - v; y := round((z - fViewPos) * fDPU); if fInverted then y := fBitmap.Height - y; if fGripsDir = gdDown then begin // DOWN fBitmap.Canvas.MoveTo( fBitmap.Width - rl, y ); fBitmap.Canvas.LineTo( fBitmap.Width - rl + ( rl div TickScale ), y ); end else begin // UP fBitmap.Canvas.MoveTo( rl - 1, y ); fBitmap.Canvas.LineTo( rl - ( rl div TickScale ) - 1, y ); end; if DrawLabel then begin lb := _FloatToLabel( z ); tw := fBitmap.Canvas.TextWidth( lb ); if fGripsDir = gdDown then begin // DOWN yy := y - ( tw div 2 ); if yy > 0 then // Don't draw half a zero fBitmap.Canvas.TextOut(fBitmap.Width, yy, lb); end else begin // UP yy := y + ( tw div 2 ); if yy - tw > 0 then // Don't draw half a zero fBitmap.Canvas.TextOut(0, yy, lb); end; end; end; end; {} begin if not fShowRuler then exit; fBitmap.Canvas.Brush.Color := GetThemeColor( ietpRuler, fRulerColor ); rl := GetRulerHeight; if fRulerDir = rdHorizontal then begin if fGripsDir = gdDown then fBitmap.Canvas.Fillrect(Rect(0, fBitmap.Height - rl, fBitmap.Width, fBitmap.Height)) else fBitmap.Canvas.Fillrect(Rect(0, 0, fBitmap.Width, rl)); end else begin if fGripsDir = gdDown then fBitmap.Canvas.Fillrect(Rect(fBitmap.Width - rl, 0, fBitmap.Width, fBitmap.Height)) else fBitmap.Canvas.Fillrect(Rect(0, 0, rl, fBitmap.Height)); end; // paint fBitmap.Canvas.Font := fFont; fontColor := GetThemeColor( ietpRulerText, fFont.Color ); fBitmap.Canvas.Font.Color := fontColor; fBitmap.Canvas.Pen.Color := fontColor; bigTickFreq := fLabelFreq; littleTickFreq := fFrequency; // Scale spacing bigTickSpacing := imax( 1, Round( fDPU * bigTickFreq )); if ( fMinLabelSpacing > 0 ) then while bigTickSpacing < fMinLabelSpacing do begin bigTickFreq := 2 * bigTickFreq ; littleTickFreq := 2 * littleTickFreq; bigTickSpacing := imax( 1, Round( fDPU * bigTickFreq )); end; if fRulerDir = rdVertical then begin // VERTICAL // pepare vertical font SaveFont := TFont.Create; SaveFont.assign(fBitmap.Canvas.Font); GetObject(SaveFont.Handle, sizeof(TLogFontA), @LogFont); if fGripsDir = gdDown then LogFont.lfEscapement := -900 // -90 degrees else LogFont.lfEscapement := 900; // 90 degrees LogFont.lfPitchAndFamily := FIXED_PITCH or FF_DONTCARE; fBitmap.Canvas.Font.Handle := CreateFontIndirectA(LogFont); // paint long ticks and text _DrawVertTicks( bigTickFreq, 2, True ); // Paint little ticks _DrawVertTicks( littleTickFreq, 4, False ); // free font fBitmap.Canvas.Font.Assign(SaveFont); FreeAndNil(SaveFont); end else begin // HORIZONTAL // Paint long ticks and text _DrawHorzTicks( bigTickFreq, 2, True ); // Paint little ticks _DrawHorzTicks( littleTickFreq, 4, False ); end; end; procedure TIERuler.SetFitInView(v: boolean); begin fFitInView := v; Update(); end; procedure TIERuler.SetDPU(v: double); begin if (csDesigning in fOwner.ComponentState) and fFitInView then exit; fDPU := v; Update(); end; procedure TIERuler.SetHexLabels(v: boolean); begin fHexLabels := v; Update(); end; procedure TIERuler.SetInverted(v: boolean); begin fInverted := v; Update(); end; procedure TIERuler.SetOffsetX(v: integer); begin fOffsetX := v; fBitmap.Width := fOwner.Width - fOffsetX; Update(); end; procedure TIERuler.SetOffsetY(v: integer); begin fOffsetY := v; fBitmap.Height := fOwner.Height - fOffsetY; Update(); end; procedure TIERuler.SetLabelPrecision(v: integer); begin fLabelPrecision := v; Update(); end; procedure TIERuler.SetMinLabelSpacing(v: integer); begin fMinLabelSpacing := v; Update(); end; procedure TIERuler.LockUpdate(); begin Inc( fLockUpdateCount ); end; procedure TIERuler.UnlockUpdate(RepaintAll: Boolean = True; DoInvalidate: Boolean = True); begin Dec( fLockUpdateCount ); if fLockUpdateCount < 1 then UpdateEx( RepaintAll, DoInvalidate ); end; procedure TIERuler.FontChange(Sender: TObject); begin Update(); end; ///////////////////////////////////////////////////////////////////////////////////////// // // // TIEViewRulerParams // // // ///////////////////////////////////////////////////////////////////////////////////////// constructor TIEViewRulerParams.Create(Owner: TControl); begin if not ( Owner is TImageEnView ) then raise EIEException.create( 'Only TImageEnView supported' ); fOwner := Owner; fHorzRuler := TIERuler.Create( Owner ); fHorzRuler.RulerDir := rdHorizontal; fHorzRuler.LabelPrecision := 2; fHorzRuler.RulerColor := clBtnShadow; fHorzRuler.ShowBorder := True; fHorzRuler.GripColorDefault := cl3DLight; fVertRuler := TIERuler.Create( Owner ); fVertRuler.RulerDir := rdVertical; fVertRuler.LabelPrecision := 2; fVertRuler.RulerColor := clBtnShadow; fVertRuler.ShowBorder := True; fVertRuler.GripColorDefault := clWindow; fSnapGrips := iesnNone; fConstrainGrips := True; fAlignToImage := False; fUnits := ieruPixels; fWasUnits := ieruPixels; fHorzPos := gdUp; fVertPos := gdLeft; fHorzHeight := 40; fVertWidth := 40; fLastMouseMoveX := -99; fLastMouseMoveY := -99; fGripsPosBase := ierbBitmap; fHorzRuler.GripsCount := 1; fVertRuler.GripsCount := 1; fHorzRuler.GripsKind[ 0 ] := gkLine; fVertRuler.GripsKind[ 0 ] := gkLine; fHorzRuler.GripsPos[ 0 ] := NON_VIZ; fVertRuler.GripsPos[ 0 ] := NON_VIZ; Font.OnChange := FontChange; Update( False ); end; destructor TIEViewRulerParams.Destroy; begin FreeAndNil( fHorzRuler ); FreeAndNil( fVertRuler ); inherited; end; // Update the ruler positions and sizes when the source TImageEnView changes size or content procedure TIEViewRulerParams.Update(DoInvalidate: Boolean = True); var z: double; ieDpiX, ieDpiY: Integer; dpux, dpuy: double; newHorzPos, newVertPos: double; hRect, vRect: TRect; I: Integer; begin if not ( HorzRulerVisible or VertRulerVisible ) then exit; fHorzRuler.LockUpdate(); fVertRuler.LockUpdate(); try if fAlignToImage then begin // Align ruler to position of the image fHorzRuler.OffsetX := TImageEnView( fOwner ).OffsetX - RulerAreaLeft; fVertRuler.OffsetY := TImageEnView( fOwner ).OffsetY - RulerAreaTop; end else begin // Photoshop style: show negative values in ruler fHorzRuler.OffsetX := 0; fVertRuler.OffsetY := 0; end; hRect := HorzRulerRect; fHorzRuler.UpdateSize( hRect.Right - hRect.Left, hRect.Bottom - hRect.Top ); vRect := VertRulerRect; fVertRuler.UpdateSize( vRect.Right - vRect.Left, vRect.Bottom - vRect.Top ); ieDpiX := TImageEnView( fOwner ).IO.Params.DpiX; ieDpiY := TImageEnView( fOwner ).IO.Params.DpiY; if ( ieDpiX < 1 ) or ( ieDpiY < 1 ) then fUnits := ieruPixels; case fUnits of ieruInches : begin dpux := ieDpiX; dpuy := ieDpiY; end; ieruMillimeters : begin dpux := ieDpiX / CM_per_Inch / 10; dpuy := ieDpiY / CM_per_Inch / 10; end; ieruCentimeters : begin dpux := ieDpiX / CM_per_Inch; dpuy := ieDpiY / CM_per_Inch; end; else { ieruPixels } begin dpux := 1; dpuy := 1; end; end; z := TImageEnView( fOwner ).Zoom / 100; newHorzPos := TImageEnView( fOwner ).ViewX / z / dpux; newVertPos := TImageEnView( fOwner ).ViewY / z / dpuy; if fAlignToImage = False then begin newHorzPos := newHorzPos - ( TImageEnView( fOwner ).OffsetX - RulerAreaLeft ) / z / dpux; newVertPos := newVertPos - ( TImageEnView( fOwner ).OffsetY - RulerAreaTop ) / z / dpuy; end; fHorzRuler.ViewPos := newHorzPos; fVertRuler.ViewPos := newVertPos; if fUnits <> fWasUnits then begin // Repositon all grips for I := 0 to fHorzRuler.GripsCount do fHorzRuler.GripsPos[ I ] := fHorzRuler.DotPerUnit / ( dpux * z ) * fHorzRuler.GripsPos[ I ]; for I := 0 to fVertRuler.GripsCount do fVertRuler.GripsPos[ I ] := fVertRuler.DotPerUnit / ( dpuy * z ) * fVertRuler.GripsPos[ I ]; end; fWasUnits := fUnits; fHorzRuler.DotPerUnit := z * dpux; fVertRuler.DotPerUnit := z * dpuy; finally fHorzRuler.UnlockUpdate( True, False ); fVertRuler.UnlockUpdate( True, False ); if DoInvalidate and ( fHorzRuler.LockUpdateCount <= 0 ) then fOwner.Invalidate(); end; end; // Draw the rulers to the TImageEnView canvas procedure TIEViewRulerParams.Paint(Canvas: TCanvas); begin {$IFDEF IEDEBUG} OutputDebugStringW( PWideChar( Format( 'Paint - %d,%d,%d,%d', [ Canvas.ClipRect.Left, Canvas.ClipRect.Top, Canvas.ClipRect.Right, Canvas.ClipRect.Bottom ]))); {$ENDIF} if HorzRulerVisible and VertRulerVisible then begin Canvas.Brush.Style := bsSolid; // There will be a corner that needs clearing if fVertPos = gdLeft then begin if fHorzPos = gdUp then begin // Top-Left Canvas.Brush.Color := GetThemeColor( ietpRuler, GetMeasureColor ); Canvas.FillRect( Rect( 0, 0, fVertWidth, fHorzHeight )); Canvas.Brush.Color := GetThemeColor( ietpRulerBackground, GetColor ); Canvas.FillRect( Rect( fHorzRuler.GetRulerHeight, fVertRuler.GetRulerHeight, fVertWidth, fHorzHeight )); if GetShowBorder() then Canvas.Pixels[ fVertWidth - 1, fHorzHeight - 1 ] := GetThemeColor( ietpRulerBorder, clBtnShadow ); end else begin // Bottom-Left Canvas.Brush.Color := GetThemeColor( ietpRuler, GetMeasureColor ); Canvas.FillRect( Rect( 0, TImageEnView( fOwner ).ClientHeight - fHorzHeight, fVertWidth, TImageEnView( fOwner ).ClientHeight )); Canvas.Brush.Color := GetThemeColor( ietpRulerBackground, GetColor ); Canvas.FillRect( Rect( fHorzRuler.GetRulerHeight, TImageEnView( fOwner ).ClientHeight - fHorzHeight, fVertWidth, TImageEnView( fOwner ).ClientHeight - fVertRuler.GetRulerHeight )); if GetShowBorder() then Canvas.Pixels[ fVertWidth - 1, TImageEnView( fOwner ).ClientHeight - fHorzHeight ] := GetThemeColor( ietpRulerBorder, clBtnShadow ); end; end else begin if fHorzPos = gdUp then begin // Top-Right Canvas.Brush.Color := GetThemeColor( ietpRuler, GetMeasureColor ); Canvas.FillRect( Rect( TImageEnView( fOwner ).ClientWidth - fVertWidth, 0, TImageEnView( fOwner ).ClientWidth, fHorzHeight )); Canvas.Brush.Color := GetThemeColor( ietpRulerBackground, GetColor ); Canvas.FillRect( Rect( TImageEnView( fOwner ).ClientWidth - fVertWidth, fVertRuler.GetRulerHeight, TImageEnView( fOwner ).ClientWidth - fHorzRuler.GetRulerHeight, fHorzHeight )); if GetShowBorder() then Canvas.Pixels[ TImageEnView( fOwner ).ClientWidth - fVertWidth, fHorzHeight - 1 ] := GetThemeColor( ietpRulerBorder, clBtnShadow ); end else begin // Bottom-Right Canvas.Brush.Color := GetThemeColor( ietpRuler, GetMeasureColor ); Canvas.FillRect( Rect( TImageEnView( fOwner ).ClientWidth - fVertWidth, TImageEnView( fOwner ).ClientHeight - fHorzHeight, TImageEnView( fOwner ).ClientWidth, TImageEnView( fOwner ).ClientHeight )); Canvas.Brush.Color := GetThemeColor( ietpRulerBackground, GetColor ); Canvas.FillRect( Rect( TImageEnView( fOwner ).ClientWidth - fVertWidth, TImageEnView( fOwner ).ClientHeight - fHorzHeight, TImageEnView( fOwner ).ClientWidth - fVertRuler.GetRulerHeight, TImageEnView( fOwner ).ClientHeight - fHorzRuler.GetRulerHeight )); if GetShowBorder() then Canvas.Pixels[ TImageEnView( fOwner ).ClientWidth - fVertWidth, TImageEnView( fOwner ).ClientHeight - fHorzHeight ] := GetThemeColor( ietpRulerBorder, clBtnShadow ); end; end end; if HorzRulerVisible then fHorzRuler.DrawToCanvas( Canvas, HorzRulerRect.Left, HorzRulerRect.Top ); if VertRulerVisible then fVertRuler.DrawToCanvas( Canvas, VertRulerRect.Left, VertRulerRect.Top ); end; // The horz ruler pos of the image left (always zero) function TIEViewRulerParams.ImageLeftOnHorzRuler(): double; begin Result := 0; end; // The horz ruler pos of the image right function TIEViewRulerParams.ImageRightOnHorzRuler(): double; var iev: TImageEnView; begin iev := TImageEnView( fOwner ); Result := ( iev.ViewX - iev.OffsetX + iev.XBmp2Scr( iev.LayersRect().Width, false )) / fHorzRuler.DotPerUnit; end; // The vert ruler pos of the image top (always zero) function TIEViewRulerParams.ImageTopOnVertRuler(): double; begin Result := 0; end; // The vert ruler pos of the image Bottom function TIEViewRulerParams.ImageBottomOnVertRuler(): double; var iev: TImageEnView; begin iev := TImageEnView( fOwner ); Result := ( iev.ViewY - iev.OffsetY + iev.YBmp2Scr( iev.LayersRect().Height, false )) / fVertRuler.DotPerUnit end; // Pass a ruler value, it is adjusted if SnapGrips or ConstrainGrips is enabled function TIEViewRulerParams.ApplyHorzConstraints(value : double; DoSnapGrips : TIERulerSnapping = iesnNone; DoConstrainGrips : Boolean = False) : double; begin Result := value; if Result = NON_VIZ then exit; case DoSnapGrips of iesnSnapToWholeNumber : Result := Round( Value ); iesnSnapToLabel : Result := Round( value / fHorzRuler.LabelFrequency ) * fHorzRuler.LabelFrequency; iesnSnapToTick : Result := Round( Value / fHorzRuler.Frequency ) * fHorzRuler.Frequency; end; if DoConstrainGrips then begin if Result < ImageLeftOnHorzRuler then Result := ImageLeftOnHorzRuler; if Result > ImageRightOnHorzRuler then Result := ImageRightOnHorzRuler; end; end; // Pass a ruler value, it is adjusted if SnapGrips or ConstrainGrips is enabled function TIEViewRulerParams.ApplyVertConstraints(value : double; DoSnapGrips : TIERulerSnapping = iesnNone; DoConstrainGrips : Boolean = False) : double; begin Result := value; if Result = NON_VIZ then exit; case DoSnapGrips of iesnSnapToWholeNumber : Result := Round( Value ); iesnSnapToLabel : Result := Round( Value / fVertRuler.LabelFrequency ) * fVertRuler.LabelFrequency; iesnSnapToTick : Result := Round( Value / fVertRuler.Frequency ) * fVertRuler.Frequency; end; if DoConstrainGrips then begin if Result < ImageTopOnVertRuler then Result := ImageTopOnVertRuler; if Result > ImageBottomOnVertRuler then Result := ImageBottomOnVertRuler; end; end; // Calculates the position on the ruler of a screen X value function TIEViewRulerParams.ScrToRulerX(X : Integer) : double; begin Result := ( X - RulerAreaLeft ) / fHorzRuler.DotPerUnit + fHorzRuler.ViewPos; end; // Calculates the position on screen for a grip position (in ruler units) function TIEViewRulerParams.RulerToScrX(Pos : Double) : Integer; begin result := round( fHorzRuler.DotPerUnit * ( Pos - fHorzRuler.ViewPos )) + RulerAreaLeft; if fHorzRuler.Inverted then result := TImageEnView( fOwner ).Width - result; end; // Calculates the position on the ruler of a screen Y value // ApplyRules: adjusts if SnapGrips or ConstrainGrips is enabled function TIEViewRulerParams.ScrToRulerY(Y : Integer) : double; begin Result := ( Y - RulerAreaTop ) / fVertRuler.DotPerUnit + fVertRuler.ViewPos; end; // Calculates the position on screen for a grip position (in ruler units) function TIEViewRulerParams.RulerToScrY(Pos : Double) : Integer; begin result := round( fVertRuler.DotPerUnit * ( Pos - fVertRuler.ViewPos )) + RulerAreaTop; if fVertRuler.Inverted then result := TImageEnView( fOwner ).Height - result; end; // Converts a value adjusted by a base value to a ruler value and adjusts if SnapGrips or ConstrainGrips is enabled function TIEViewRulerParams.ValueToRulerX(Value : double; ValueBase: TIERulerPosBase) : double; begin case ValueBase of ierbBitmap : Result := ScrToRulerX( TImageEnView( fOwner ).XBmp2Scr( Round( Value ), false)); ierbScreen : Result := ScrToRulerX( Round( Value )); else { ierbRuler } Result := Value; end; end; // Converts a ruler value to a base format function TIEViewRulerParams.RulerToValueX(Pos : double; ValueBase: TIERulerPosBase) : double; begin case ValueBase of ierbBitmap : Result := TImageEnView( fOwner ).XScr2Bmp( Round( RulerToScrX( Pos{ + RulerAreaLeft} )), false); ierbScreen : Result := Round( RulerToScrX( Pos )); else { ierbRuler } Result := Pos; end; end; // Converts a value adjusted by a base value to a ruler value and adjusts if SnapGrips or ConstrainGrips is enabled function TIEViewRulerParams.ValueToRulerY(Value : double; ValueBase: TIERulerPosBase) : double; begin case ValueBase of ierbBitmap : Result := ScrToRulerY( TImageEnView( fOwner ).YBmp2Scr( Round( Value ), false)); ierbScreen : Result := ScrToRulerY( Round( Value )); else { ierbRuler } Result := Value; end; end; // Converts a ruler value to a base format function TIEViewRulerParams.RulerToValueY(Pos : Double; ValueBase: TIERulerPosBase) : Double; begin case ValueBase of ierbBitmap : result := TImageEnView( fOwner ).YScr2Bmp( Round( RulerToScrY( Pos {+ RulerAreaTop} )), false); ierbScreen : result := Round( RulerToScrY( Pos )); else { ierbRuler } Result := Pos; end; end; // Ensures all grips are adjusted by SnapGrips or ConstrainGrips procedure TIEViewRulerParams.CheckGripBounds(); var aGripsPos: TIERulerPosBase; I: Integer; begin if ( fConstrainGrips = False ) and ( fSnapGrips = iesnNone ) then exit; aGripsPos := fGripsPosBase; LockUpdate(); try fGripsPosBase := ierbRuler; for I := 0 to fHorzRuler.GripsCount - 1 do fHorzRuler.GripsPos[ I ] := ApplyHorzConstraints( ScrToRulerX( RulerToScrX( fHorzRuler.GripsPos[ I ] )), fSnapGrips, fConstrainGrips ); for I := 0 to fVertRuler.GripsCount - 1 do fVertRuler.GripsPos[ I ] := ApplyVertConstraints( ScrToRulerY( RulerToScrY( fVertRuler.GripsPos[ I ] )), fSnapGrips, fConstrainGrips ); finally fGripsPosBase := aGripsPos; UnlockUpdate(); end; end; // Call from TImageEnView MouseDown event procedure TIEViewRulerParams.HandleMouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if PtInRect( HorzRulerRect, Point( x, y )) then fHorzRuler.HandleMouseDown( Button, Shift, X - HorzRulerRect.Left, Y - HorzRulerRect.Top ) else if PtInRect( VertRulerRect, Point( x, y )) then fVertRuler.HandleMouseDown( Button, Shift, X - VertRulerRect.Left, Y - VertRulerRect.Top ) else begin fHorzRuler.SelectedGrip := -1; fHorzRuler.SelectedGrip := -1; end; end; procedure TIEViewRulerParams.MouseMoveOutsideRuler(Shift: TShiftState; X, Y: Integer); begin if GetCursorGripKind = gkNone then exit; LockUpdate(); try if fHorzRuler.GripsCount < 1 then fHorzRuler.GripsCount := 1; if fVertRuler.GripsCount < 1 then fVertRuler.GripsCount := 1; if fHorzRuler.Inverted then X := fOwner.ClientWidth - X + RulerAreaLeft - RulerAreaRight; if fVertRuler.Inverted then Y := fOwner.ClientHeight - Y + RulerAreaTop - RulerAreaBottom; // iesnNone because we don't snap cursor grips fHorzRuler.GripsPos[ 0 ] := ApplyHorzConstraints( ScrToRulerX( X ), iesnNone, fConstrainGrips ); // Cursor grip fVertRuler.GripsPos[ 0 ] := ApplyVertConstraints( ScrToRulerY( Y ), iesnNone, fConstrainGrips ); // Cursor grip finally UnlockUpdate( False, True ); end; end; procedure TIEViewRulerParams.ConstrainGripsCB(Sender: TObject; var GripPos: double); begin case TIERuler( Sender ).RulerDir of rdHorizontal : GripPos := ApplyHorzConstraints( GripPos, fSnapGrips, fConstrainGrips ); rdVertical : GripPos := ApplyVertConstraints( GripPos, fSnapGrips, fConstrainGrips ); end; end; // Call from TImageEnView MouseMove event // Result is true if mouse movement is over rulers function TIEViewRulerParams.HandleMouseMove(Shift: TShiftState; X, Y: Integer) : Boolean; begin if ( TImageEnView( fOwner ).MouseCapture = False ) and ( fLastMouseMoveX = X ) and ( fLastMouseMoveY = Y ) and ( fLastMouseMoveShift = Shift ) then begin Result := fLastMouseMoveResult; exit; end; Result := False; {$IFDEF IEDEBUG} OutputDebugStringW( PWideChar( Format( 'MouseMove - %d,%d', [ X, Y ]))); {$ENDIF} // don't use PtInRect to allow them to drag outside the rect area if ( Y >= HorzRulerRect.Top ) and ( Y <= HorzRulerRect.Bottom ) then begin Result := True; fHorzRuler.HandleMouseMoveEx( Shift, X - HorzRulerRect.Left, Y - HorzRulerRect.Top, ConstrainGripsCB ); end; // Don't use else, as potentially both might need to be called if ( X >= VertRulerRect.Left ) and ( X <= VertRulerRect.Top ) then begin Result := True; fVertRuler.HandleMouseMoveEx( Shift, X - VertRulerRect.Left, Y - VertRulerRect.Top, ConstrainGripsCB ); end; if not Result then MouseMoveOutsideRuler( Shift, X, Y ); fLastMouseMoveX := X; fLastMouseMoveY := Y; fLastMouseMoveShift := Shift; fLastMouseMoveResult := Result; end; // Call from TImageEnView MouseUp event procedure TIEViewRulerParams.HandleMouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if PtInRect( HorzRulerRect, Point( x, y )) then fHorzRuler.HandleMouseUp( Button, Shift, X - HorzRulerRect.Left, Y - HorzRulerRect.Top ) else if PtInRect( VertRulerRect, Point( x, y )) then fVertRuler.HandleMouseUp( Button, Shift, X - VertRulerRect.Left, Y - VertRulerRect.Top ); end; procedure TIEViewRulerParams.HandleSpecialKey(CharCode: Word; Shift: TShiftState); var newPos, moveBy: double; begin if ssShift in Shift then moveBy := fHorzRuler.LabelFrequency else moveBy := fHorzRuler.Frequency; case CharCode of VK_LEFT : if HorzRulerVisible and ( fHorzRuler.SelectedGrip > 0 ) then begin newPos := fHorzRuler.GripsPos[ fHorzRuler.SelectedGrip ] - moveBy; if fConstrainGrips and ( newPos < ImageLeftOnHorzRuler ) then newPos := ImageLeftOnHorzRuler; fHorzRuler.GripsPos[ fHorzRuler.SelectedGrip ] := newPos; ScrollToHorzGrip( fHorzRuler.SelectedGrip - 1 ); end; VK_RIGHT : if HorzRulerVisible and ( fHorzRuler.SelectedGrip > 0 ) then begin newPos := fHorzRuler.GripsPos[ fHorzRuler.SelectedGrip ] + moveBy; if fConstrainGrips and ( newPos > ImageRightOnHorzRuler ) then newPos := ImageRightOnHorzRuler; fHorzRuler.GripsPos[ fHorzRuler.SelectedGrip ] := newPos; ScrollToHorzGrip( fHorzRuler.SelectedGrip - 1 ); end; VK_UP : if VertRulerVisible and ( fVertRuler.SelectedGrip > 0 ) then begin newPos := fVertRuler.GripsPos[ fVertRuler.SelectedGrip ] - moveBy; if fConstrainGrips and ( newPos < ImageTopOnVertRuler ) then newPos := ImageTopOnVertRuler; fVertRuler.GripsPos[ fVertRuler.SelectedGrip ] := newPos; ScrollToVertGrip( fVertRuler.SelectedGrip - 1 ); end; VK_DOWN : if VertRulerVisible and ( fVertRuler.SelectedGrip > 0 ) then begin newPos := fVertRuler.GripsPos[ fVertRuler.SelectedGrip ] + moveBy; if fConstrainGrips and ( newPos > ImageBottomOnVertRuler ) then newPos := ImageBottomOnVertRuler; fVertRuler.GripsPos[ fVertRuler.SelectedGrip ] := newPos; ScrollToVertGrip( fVertRuler.SelectedGrip - 1 ); end; end; end; {!! TIEViewRulerParams.HorzGripsMin Declaration property HorzGripsMin[g: integer]: double; Description Specifies the minimum position of the grip, g, on the horizontal ruler. Use to determine whether to pass bitmap, ruler or screen values. Notes: - By default, all grips are contrained to the image area () - To access the cursor grip (showing the current position of the cursor over the image), use HorzGripsMin[ -1 ] !!} function TIEViewRulerParams.GetHorzGripsMin(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueX( fHorzRuler.GripsMin[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetHorzGripsMin(i: integer; v: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fHorzRuler.GripsMin[ i + 1 ] := ValueToRulerX( v, fGripsPosBase ); end; {!! TIEViewRulerParams.HorzGripsMax Declaration property HorzGripsMax[g: integer]: double; Description Specifies the max position of the grip, g, on the horizontal ruler. Use to determine whether to pass bitmap, ruler or screen values. Notes: - By default, all grips are contrained to the image area () - To access the cursor grip (showing the current position of the cursor over the image), use HorzGripsMax[ -1 ] !!} function TIEViewRulerParams.GetHorzGripsMax(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueX( fHorzRuler.GripsMax[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetHorzGripsMax(i: integer; v: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fHorzRuler.GripsMax[ i + 1 ] := ValueToRulerX( v, fGripsPosBase ); end; {!! TIEViewRulerParams.VertGripsMin Declaration property VertGripsMin[g: integer]: double; Description Specifies the minimum position of the grip, g, on the vertical ruler. Use to determine whether to pass bitmap, ruler or screen values. Notes: - By default, all grips are contrained to the image area () - To access the cursor grip (showing the current position of the cursor over the image), use VertGripsMin[ -1 ] !!} function TIEViewRulerParams.GetVertGripsMin(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueY( fVertRuler.GripsMin[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetVertGripsMin(i: integer; v: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsMin[ i + 1 ] := ValueToRulerY( v, fGripsPosBase ); end; {!! TIEViewRulerParams.VertGripsMax Declaration property VertGripsMax[g: integer]: double; Description Specifies the max position of the grip, g, on the vertical ruler. Use to determine whether to pass bitmap, ruler or screen values. Notes: - By default, all grips are contrained to the image area () - To access the cursor grip (showing the current position of the cursor over the image), use VertGripsMax[ -1 ] !!} function TIEViewRulerParams.GetVertGripsMax(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueY( fVertRuler.GripsMax[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetVertGripsMax(i: integer; v: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsMax[ i + 1 ] := ValueToRulerY( v, fGripsPosBase ); end; {!! TIEViewRulerParams.MinLabelSpacing Declaration property MinLabelSpacing: integer; Description Specifies the minimum spacing between (the center of) labels. To reduce crowding, labels positioned closer than this are not shown. If MinLabelSpacing is 0 then labels are always drawn. Default: 30 Example ImageEnView1.RulerParams.MinLabelSpacing := 0; !!} function TIEViewRulerParams.GetMinLabelSpacing: integer; begin result := fHorzRuler.MinLabelSpacing; end; procedure TIEViewRulerParams.SetMinLabelSpacing(v: integer); begin LockUpdate(); fHorzRuler.MinLabelSpacing := v; fVertRuler.MinLabelSpacing := v; UnlockUpdate(); end; {!! TIEViewRulerParams.Frequency Declaration property Frequency: double; Description Specifies the number of logical units where ticks are shown. Use to configure labels and longer tick marks. Note: This value is set automatically when changing . Default: 10 Example ImageEnView1.LockUpdate(); ImageEnView1.RulerParams.Units := ieruInches; ImageEnView1.RulerParams.LabelFrequency := 1/4; // Labels every quarter inch ImageEnView1.RulerParams.Frequency := 1/32; // Ticks every 1/32 inch ImageEnView1.UnlockUpdate(); !!} function TIEViewRulerParams.GetFrequency: double; begin result := fHorzRuler.Frequency; end; procedure TIEViewRulerParams.SetFrequency(v: double); begin LockUpdate(); fHorzRuler.Frequency := v; fVertRuler.Frequency := v; UnlockUpdate(); end; {!! TIEViewRulerParams.LabelFrequency Declaration property LabelFrequency: double; Description Specifies the number of logical units where to show the labels (and longer tick marks). Use to configure short tick marks. Notes: - This value is set automatically when changing . - Labels may be hidden if the view is crowded and has been set Default: 40 Example ImageEnView1.LockUpdate(); ImageEnView1.RulerParams.Units := ieruInches; ImageEnView1.RulerParams.LabelFrequency := 1/4; // Labels every quarter inch ImageEnView1.RulerParams.Frequency := 1/32; // Ticks every 1/32 inch ImageEnView1.UnlockUpdate(); !!} function TIEViewRulerParams.GetLabelFrequency: double; begin result := fHorzRuler.LabelFrequency; end; procedure TIEViewRulerParams.SetLabelFrequency(v: double); begin LockUpdate(); fHorzRuler.LabelFrequency := v; fVertRuler.LabelFrequency := v; UnlockUpdate(); end; {!! TIEViewRulerParams.ShowMeasure Declaration property ShowMeasure: boolean; Description Specify whether a measurement block is drawn on the ruler. Default: True Example // Show only grips ImageEnView1.RulerParams.ShowMeasure := False; ImageEnView1.RulerParams.HorzHeight := 10; ImageEnView1.RulerParams.VertWidth := 10; !!} function TIEViewRulerParams.GetShowMeasure: boolean; begin result := fHorzRuler.ShowRuler; end; procedure TIEViewRulerParams.SetShowMeasure(v: boolean); begin LockUpdate(); fHorzRuler.ShowRuler := v; fVertRuler.ShowRuler := v; UnlockUpdate(); end; {!! TIEViewRulerParams.ShowBorder Declaration property ShowBorder: boolean; Description Specify whether a border is displayed between the ruler and the image. Default: True Example // Show only cursor position ImageEnView1.RulerParams.ShowMeasure := False; ImageEnView1.RulerParams.ShowBorder := False; ImageEnView1.RulerParams.HorzHeight := 10; ImageEnView1.RulerParams.VertWidth := 10; !!} function TIEViewRulerParams.GetShowBorder: boolean; begin Result := fHorzRuler.ShowBorder; end; procedure TIEViewRulerParams.SetShowBorder(const Value: boolean); begin LockUpdate(); fHorzRuler.ShowBorder := Value; fVertRuler.ShowBorder := Value; UnlockUpdate(); end; {!! TIEViewRulerParams.MeasureColor Declaration property MeasureColor: TColor; Description Specifies the color of the measurement block of the ruler. Note: This value may be overridden if is enabled. Default: clBtnFace See Also - !!} function TIEViewRulerParams.GetMeasureColor: TColor; begin result := fHorzRuler.RulerColor; end; procedure TIEViewRulerParams.SetMeasureColor(v: TColor); begin LockUpdate(); fHorzRuler.RulerColor := v; fVertRuler.RulerColor := v; UnlockUpdate(); end; {!! TIEViewRulerParams.Color Declaration property Color: TColor; Description Specifies the color of the background (excluding area of the measurement block). Note: This value may be overridden if is enabled. Default: clBtnShadow See Also - !!} // return -1 = none function TIEViewRulerParams.GetColor: TColor; begin result := fHorzRuler.Background; end; procedure TIEViewRulerParams.SetColor(c: TColor); begin LockUpdate(); fHorzRuler.Background := c; fVertRuler.Background := c; UnlockUpdate(); end; {!! TIEViewRulerParams.HorzInverted Declaration property HorzInverted: boolean; Description When true, the horizontal ruler is painted from right to left. Default: False Example // Draw a right-hand side UI ImageEnView1.LockUpdate(); ImageEnView1.ShowRulers := [ rdVertical, rdHorizontal ]; ImageEnView1.RulerParams.VertPos := gdRight; // Ruler on RHS ImageEnView1.RulerParams.HorzInverted := True; // Horz ruler reversed measurement ImageEnView1.UnlockUpdate(); See Also - - - !!} function TIEViewRulerParams.GetHorzInverted: boolean; begin result := fHorzRuler.Inverted; end; procedure TIEViewRulerParams.SetHorzInverted(v: boolean); begin fHorzRuler.Inverted := v; end; {!! TIEViewRulerParams.VertInverted Declaration property VertInverted: boolean; Description When true, the vertical ruler is painted from bottom to top. Default: False. Example // Draw ruler from bottom to top ImageEnView1.RulerParams.VertInverted := True; See Also - - - !!} function TIEViewRulerParams.GetVertInverted: boolean; begin result := fVertRuler.Inverted; end; procedure TIEViewRulerParams.SetVertInverted(v: boolean); begin fVertRuler.Inverted := v; end; {!! TIEViewRulerParams.LabelPrecision Declaration property LabelPrecision: integer; Description Specifies the number of decimal places shown for values in the ruler. Default: 2 Example ImageEnView1.LockUpdate(); ImageEnView1.RulerParams.Units := ieruCentimeters; ImageEnView1.RulerParams.LabelPrecision := 1; // Show labels to one decimal place ImageEnView1.UnlockUpdate(); !!} function TIEViewRulerParams.GetLabelPrecision: integer; begin result := fHorzRuler.LabelPrecision; end; procedure TIEViewRulerParams.SetLabelPrecision(v: integer); begin LockUpdate(); fHorzRuler.LabelPrecision := v; fVertRuler.LabelPrecision := v; UnlockUpdate(); end; {!! TIEViewRulerParams.ScrollRate Declaration property ScrollRate: double; Description Specifies the scroll rate used when moving a grip out of ruler borders. Default: 1.0 !!} function TIEViewRulerParams.GetScrollRate: double; begin result := fHorzRuler.ScrollRate; end; procedure TIEViewRulerParams.SetScrollRate(const Value: double); begin fHorzRuler.ScrollRate := Value; fVertRuler.ScrollRate := Value; end; {!! TIEViewRulerParams.CursorGripKind Declaration property CursorGripKind: ; Description Specifies the style for the grip that appears on the ruler showing the current position of the cursor over the image. Default: gkLine Note: You can access other properties of the cursor grips, using index -1 in the horizontal and vertical grip arrays. i.e. ImageEnView1.RulerParams.CursorGripKind := gkTriangle; Is the same as setting: ImageEnView1.RulerParams.HorzGripsKind[ -1 ] := gkTriangle; ImageEnView1.RulerParams.VertGripsKind[ -1 ] := gkTriangle; Example // Hide the cursor grip ImageEnView1.RulerParams.CursorGripKind := gkNone; // Set the cursor grip to a red triangle ImageEnView1.RulerParams.CursorGripKind := gkTriangle; ImageEnView1.RulerParams.HorzGripsColor[ -1 ] := clRed; ImageEnView1.RulerParams.VertGripsColor[ -1 ] := clRed; See Also - - - - - !!} function TIEViewRulerParams.GetCursorGripKind: TGripKind; begin result := GetHorzGripsKind( -1 ); end; procedure TIEViewRulerParams.SetCursorGripKind(const Value: TGripKind); begin SetHorzGripsKind( -1, Value ); SetVertGripsKind( -1, Value ); end; {!! TIEViewRulerParams.GripKindDefault Declaration property GripKindDefault: ; Description Specifies the default style for all grips. This style will be assigned to any grips for which you have not set a custom style using or . Notes: - The size of the grip is specified by and . - This property does not affect the grip for the current cursor position, use instead Default: gkTriangle Example // Set default style of grips to gkTriangle, but gkArrow2 to grips > 10 ImageEnView1.RulerParams.GripKindDefault := gkTriangle; for i := 10 to ImageEnView1.RulerParams.HorzGripsCount - 1 do ImageEnView1.RulerParams.HorzGripsKind[ i ] := gkArrow2; See Also - - - - - - - !!} function TIEViewRulerParams.GetGripKindDefault: TGripKind; begin result := fHorzRuler.GripKindDefault; end; procedure TIEViewRulerParams.SetGripKindDefault(const Value: TGripKind); begin LockUpdate(); fHorzRuler.GripKindDefault := Value; fVertRuler.GripKindDefault := Value; UnlockUpdate(); end; {!! TIEViewRulerParams.GripColorDefault Declaration property GripColorDefault: TColor; Description Specifies the brush color of all grips. This color will be assigned to any grips for which you have not set a custom color using or . Notes: - This value may be overridden if is enabled. - You can set the pen color with Default: cl3DLight Example // Set default color of grips to clSilver, but clRed to grips > 10 ImageEnView1.RulerParams.GripColorDefault := clSilver; for i := 10 to ImageEnView1.RulerParams.HorzGripsCount - 1 do ImageEnView1.RulerParams.HorzGripsColor[ i ] := clRed; See Also - - - - !!} function TIEViewRulerParams.GetGripColorDefault: TColor; begin result := fHorzRuler.GripColorDefault; end; procedure TIEViewRulerParams.SetGripColorDefault(const Value: TColor); begin LockUpdate(); fHorzRuler.GripColorDefault := Value; fVertRuler.GripColorDefault := Value; UnlockUpdate(); end; {!! TIEViewRulerParams.GripPenColor Declaration property GripPenColor: TColor; Description Specifies the pen (border) color of all grips. Notes: - This value may be overridden if is enabled. - The brush color is specified by , or for individual grips with or . Default: clWindowFrame See Also - - - - - - !!} function TIEViewRulerParams.GetGripPenColor: TColor; begin result := fHorzRuler.GripPenColor; end; procedure TIEViewRulerParams.SetGripPenColor(const Value: TColor); begin LockUpdate(); fHorzRuler.GripPenColor := Value; fVertRuler.GripPenColor := Value; UnlockUpdate(); end; {!! TIEViewRulerParams.GripWidth Declaration property GripWidth: integer; Description Specifies the width of grip triangles in pixels. Default: 12 See Also - - !!} function TIEViewRulerParams.GetGripWidth: integer; begin result := fHorzRuler.GripBaseDim; end; procedure TIEViewRulerParams.SetGripWidth(v: integer); begin LockUpdate(); fHorzRuler.GripBaseDim := v; fVertRuler.GripBaseDim := v; UnlockUpdate(); end; {!! TIEViewRulerParams.GripHeight Declaration property GripHeight: integer; Description Specifies the maximum height of the grip. Default: 15 Note: The value may be automatically adjusted depending on your font size and the available height/width. Example // Create narrow rulers ImageEnView1.RulerParams.Font.Size := 6; ImageEnView1.RulerParams.HorzHeight := 20; ImageEnView1.RulerParams.VertWidth := 20; ImageEnView1.RulerParams.GripHeight := 10; See Also - - !!} function TIEViewRulerParams.GetGripHeight: integer; begin result := fHorzRuler.MaxGripHeight; end; procedure TIEViewRulerParams.SetGripHeight(const Value: integer); begin LockUpdate(); fHorzRuler.MaxGripHeight := Value; fVertRuler.MaxGripHeight := Value; UnlockUpdate(); end; {!! TIEViewRulerParams.HorzGripsPos Declaration property HorzGripsPos[g: integer]: double; Description Specifies the current position of the grip, g, on the horizontal ruler. Use to determine whether to pass bitmap, ruler or screen values. Example // Add three grips at 25%, 50% and 75% of the image width ImageEnView1.RulerParams.HorzGripsCount := 3; ImageEnView1.RulerParams.GripsPosBase := ierbBitmap; // Units are relative to the bitmap ImageEnView1.RulerParams.HorzGripsPos[ 0 ] := MulDiv( ImageEnView1.IEBitmap.Width, 1, 4 ); ImageEnView1.RulerParams.HorzGripsPos[ 1 ] := MulDiv( ImageEnView1.IEBitmap.Width, 2, 4 ); ImageEnView1.RulerParams.HorzGripsPos[ 2 ] := MulDiv( ImageEnView1.IEBitmap.Width, 3, 4 ); !!} function TIEViewRulerParams.GetHorzGripsPos(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueX( fHorzRuler.GripsPos[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetHorzGripsPos(i: integer; p: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fHorzRuler.GripsPos[ i + 1 ] := ApplyHorzConstraints( ValueToRulerX( p, fGripsPosBase ), fSnapGrips, fConstrainGrips ); end; {!! TIEViewRulerParams.HorzGripsCount Declaration property HorzGripsCount: integer; Description Specifies the number of the grips on the horizontal ruler. Default: 0 Examples // Clear added grips ImageEnView1.RulerParams.HorzGripsCount := 0; // Add twenty grips ImageEnView1.RulerParams.HorzGripsCount := 20; // Set default color of grips to clSilver, but clRed for grips > 10 ImageEnView1.RulerParams.GripColorDefault := clSilver; for i := 10 to ImageEnView1.RulerParams.HorzGripsCount - 1 do ImageEnView1.RulerParams.HorzGripsColor[ i ] := clRed; !!} function TIEViewRulerParams.GetHorzGripsCount: integer; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fHorzRuler.GripsCount - 1; end; procedure TIEViewRulerParams.SetHorzGripsCount(v: integer); begin // Offset index by 1 to obscure grip 0, the cursor grip fHorzRuler.GripsCount := imax( 1, v + 1 ); end; {!! TIEViewRulerParams.HorzGripsKind Declaration property HorzGripsKind[g: integer]: ; Description Specifies the style of the grip, g, on the horizontal ruler (triangle, arrow, etc). Notes: - The default style for grips is specified by . Use when you want individual grips with different styles - The style of the grip showing the current cursor position is specified by - The size of the grip is specified by and Examples // Set default style of grips to gkTriangle, but gkArrow2 to grips > 10 ImageEnView1.RulerParams.GripKindDefault := gkTriangle; for i := 10 to ImageEnView1.RulerParams.HorzGripsCount - 1 do ImageEnView1.RulerParams.HorzGripsKind[ i ] := gkArrow2; See Also - - - - - - !!} function TIEViewRulerParams.GetHorzGripsKind(i: integer): TGripKind; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fHorzRuler.GripsKind[ i + 1 ]; end; procedure TIEViewRulerParams.SetHorzGripsKind(i: integer; v: TGripKind); begin // Offset index by 1 to obscure grip 0, the cursor grip fHorzRuler.GripsKind[ i + 1 ] := v; end; {!! TIEViewRulerParams.HorzGripsColor Declaration property HorzGripsColor[g: integer]: TColor; Description Specifies the brush color of the grip, g, on the horizontal ruler. Notes: - The default color of all grips is set by . Use HorzGripsColor to assign custom colors to specific grips. - To access the cursor grip (showing the current position of the cursor over the image), use HorzGripsColor[ -1 ] You can set the pen color with Example // Set default color of grips to clSilver, but clRed for grips > 10 ImageEnView1.RulerParams.GripColorDefault := clSilver; for i := 10 to ImageEnView1.RulerParams.HorzGripsCount - 1 do ImageEnView1.RulerParams.HorzGripsColor[ i ] := clRed; // Set the cursor grip to a red triangle ImageEnView1.RulerParams.HorzGripsKind[ -1 ] := gkTriangle; // Same as setting CursorGripKind ImageEnView1.RulerParams.HorzGripsColor[ -1 ] := clRed; See Also - - - - - - !!} function TIEViewRulerParams.GetHorzGripsColor(i: integer): TColor; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fHorzRuler.GripsColor[ i + 1 ]; end; procedure TIEViewRulerParams.SetHorzGripsColor(i: integer; p: TColor); begin fHorzRuler.GripsColor[ i + 1 ] := p; end; {!! TIEViewRulerParams.VertGripsPos Declaration property VertGripsPos[g: integer]: double; Description Specifies the current position of the grip, g, on the vertical ruler. Use to determine whether to pass bitmap, ruler or screen values. Example // Add three grips at 25%, 50% and 75% of the image height ImageEnView1.RulerParams.VertGripsCount := 3; ImageEnView1.RulerParams.GripsPosBase := ierbBitmap; // Units are relative to the bitmap ImageEnView1.RulerParams.VertGripsPos[ 0 ] := MulDiv( ImageEnView1.IEBitmap.Height, 1, 4 ); ImageEnView1.RulerParams.VertGripsPos[ 1 ] := MulDiv( ImageEnView1.IEBitmap.Height, 2, 4 ); ImageEnView1.RulerParams.VertGripsPos[ 2 ] := MulDiv( ImageEnView1.IEBitmap.Height, 3, 4 ); !!} function TIEViewRulerParams.GetVertGripsPos(i: integer): double; begin // Offset index by 1 to obscure grip 0, the cursor grip result := RulerToValueY( fVertRuler.GripsPos[ i + 1 ], fGripsPosBase ); end; procedure TIEViewRulerParams.SetVertGripsPos(i: integer; p: double); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsPos[ i + 1 ] := ApplyVertConstraints(ValueToRulerY( p, fGripsPosBase ), fSnapGrips, fConstrainGrips ); end; {!! TIEViewRulerParams.VertGripsCount Declaration property VertGripsCount: integer; Description Specifies the number of the grips on the vertical ruler. Default: 0 Examples // Clear all grips ImageEnView1.RulerParams.VertGripsCount := 0; // Add twenty grips ImageEnView1.RulerParams.VertGripsCount := 20; // Set default color of grips to clSilver, but clRed for grips > 10 ImageEnView1.RulerParams.GripColorDefault := clSilver; for i := 10 to ImageEnView1.RulerParams.VertGripsCount - 1 do ImageEnView1.RulerParams.VertGripsColor[ i ] := clRed; !!} function TIEViewRulerParams.GetVertGripsCount: integer; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fVertRuler.GripsCount - 1; end; procedure TIEViewRulerParams.SetVertGripsCount(v: integer); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsCount := imax( 1, v + 1 ) end; {!! TIEViewRulerParams.VertGripsKind Declaration property VertGripsKind[g: integer]: ; Description Specifies the style of the grip, g, on the vertical ruler (triangle, arrow, etc). Notes: - The default style for grips is specified by . Use when you want individual grips with different styles - The style of the grip showing the current cursor position is specified by - The size of the grip is specified by and Example // Set default style of grips to gkTriangle, but gkArrow2 to grips > 10 ImageEnView1.RulerParams.GripKindDefault := gkTriangle; for i := 10 to ImageEnView1.RulerParams.VertGripsCount - 1 do ImageEnView1.RulerParams.VertGripsKind[ i ] := gkArrow2; // Set the cursor grip to a red triangle ImageEnView1.RulerParams.VertGripsKind[ -1 ] := gkTriangle; // Same as setting CursorGripKind ImageEnView1.RulerParams.VertGripsColor[ -1 ] := clRed; See Also - - - - - - !!} function TIEViewRulerParams.GetVertGripsKind(i: integer): TGripKind; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fVertRuler.GripsKind[ i + 1 ]; end; procedure TIEViewRulerParams.SetVertGripsKind(i: integer; v: TGripKind); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsKind[ i + 1 ] := v; end; {!! TIEViewRulerParams.VertGripsColor Declaration property VertGripsColor[g: integer]: TColor; Description Specifies the brush color of the grip, g, on the vertical ruler. Notes: - The default color of all grips is set by . Use VertGripsColor to assign custom colors to specific grips. - To access the cursor grip (showing the current position of the cursor over the image), use VertGripsColor[ -1 ] You can set the pen color with Example // Set default color of grips to clSilver, but clRed for grips > 10 ImageEnView1.RulerParams.GripColorDefault := clSilver; for i := 10 to ImageEnView1.RulerParams.VertGripsCount - 1 do ImageEnView1.RulerParams.VertGripsColor[ i ] := clRed; See Also - - - - - - !!} function TIEViewRulerParams.GetVertGripsColor(i: integer): TColor; begin // Offset index by 1 to obscure grip 0, the cursor grip result := fVertRuler.GripsColor[ i + 1 ]; end; procedure TIEViewRulerParams.SetVertGripsColor(i: integer; p: TColor); begin // Offset index by 1 to obscure grip 0, the cursor grip fVertRuler.GripsColor[ i + 1 ] := p; end; {!! TIEViewRulerParams.Font Declaration property Font: TFont; Description Specifies the font used for label text. Note: The color of this font may be overridden if is enabled. Example // Create narrow rulers ImageEnView1.RulerParams.Font.Size := 6; ImageEnView1.RulerParams.HorzHeight := 20; ImageEnView1.RulerParams.VertWidth := 20; ImageEnView1.RulerParams.GripHeight := 10; !!} function TIEViewRulerParams.GetFont: TFont; begin result := fHorzRuler.Font; end; procedure TIEViewRulerParams.FontChange(Sender: TObject); begin fVertRuler.Font.Assign( Font ); end; {!! TIEViewRulerParams.SnapGrips Declaration property SnapGrips: ; Description Specifies whether grips snap to the closest label or whole number on the ruler. Description Item Description iesnNone Do not adjust grip positions iesnSnapToTick Automatically move grips to the nearest tick iesnSnapToLabel Automatically move grips to the nearest label (long tick) iesnSnapToWholeNumber Automatically move grips to the nearest whole value on the ruler (e.g. move to 2.0 inches)
Default: iesnNone Example // Snap to the nearest label tick ImageEnView1.RulerParams.SnapGrips := iesnSnapToLabel; // Snap to the nearest whole number on the ruler ImageEnView1.RulerParams.SnapGrips := iesnSnapToWholeNumber; !!} procedure TIEViewRulerParams.SetSnapGrips(Value: TIERulerSnapping); begin fSnapGrips := Value; // Snap existing grips CheckGripBounds(); end; {!! TIEViewRulerParams.ConstrainGrips Declaration property ConstrainGrips: Boolean; Description Specifies whether grips can be dragged outside the area of the image. Default: True Example // Allow dragging of grips outside the area of the image ImageEnView1.RulerParams.ConstrainGrips := False; !!} procedure TIEViewRulerParams.SetConstrainGrips(Value: Boolean); begin fConstrainGrips := Value; // Constrain existing grips CheckGripBounds(); end; {!! TIEViewRulerParams.AlignToImage Declaration property AlignToImage: Boolean; Description If false, the ruler will be the full width of the control (and show negative values for areas outside the image). If true, the ruler begins at the position of the image within the control. Default: False !!} procedure TIEViewRulerParams.SetAlignToImage(Value: Boolean); begin fAlignToImage := Value; Update(); end; {!! TIEViewRulerParams.Units Declaration property Units:
; Description Specifies the measurement unit displayed on the ruler. Default: ieruPixels Note: Changing Units will automatically set and to a relevant value Example ImageEnView1.LockUpdate(); ImageEnView1.RulerParams.Units := ieruInches; ImageEnView1.RulerParams.LabelFrequency := 1/4; // Labels every quarter inch ImageEnView1.RulerParams.Frequency := 1/32; // Ticks every 1/32 inch ImageEnView1.UnlockUpdate(); !!} procedure TIEViewRulerParams.SetUnits(Value: TIERulerUnits); var lfrq, tfrq: double; begin if fUnits = Value then exit; LockUpdate(); try fUnits := Value; case fUnits of ieruInches: begin lfrq := 0.25; // Every quarter inch tfrq := lfrq / 8; end; ieruMillimeters: begin lfrq := 2.5; // Every 2.5 mm tfrq := lfrq / 5; end; ieruCentimeters: begin lfrq := 0.25; // Every quarter CM tfrq := lfrq / 5; end; else { ieruPixels } begin lfrq := 100; // Every 100px tfrq := lfrq / 10; end; end; fHorzRuler.Frequency := tfrq; fVertRuler.Frequency := tfrq; fHorzRuler.LabelFrequency := lfrq; fVertRuler.LabelFrequency := lfrq; finally UnlockUpdate(); end; end; {!! TIEViewRulerParams.HorzPos Declaration property HorzPos: ; Description Specifies Whether the horizontal ruler is shown above (gdUp) or below (gdDown) the image. Default: gdUp Example // Draw a horizontal ruler on bottom of image ImageEnView1.LockUpdate(); ImageEnView1.ShowRulers := [ rdHorizontal ]; ImageEnView1.RulerParams.VertPos := gdDown; ImageEnView1.UnlockUpdate(); See Also - - - !!} procedure TIEViewRulerParams.SetHorzPos(Value: TGripsDir); begin if fHorzPos <> Value then begin fHorzPos := Value; fHorzRuler.GripsDir := Value; TImageEnView( fOwner).Update(); end; end; {!! TIEViewRulerParams.VertPos Declaration property VertPos: ; Description Specifies whether the vertical ruler is shown left (gdLeft) or right (gdRight) of the image. Default: gdLeft Example // Draw a vertical ruler on right of image ImageEnView1.LockUpdate(); ImageEnView1.ShowRulers := [ rdVertical ]; ImageEnView1.RulerParams.VertPos := gdRight; ImageEnView1.UnlockUpdate(); See Also - - - !!} procedure TIEViewRulerParams.SetVertPos(Value: TGripsXDir); begin if fVertPos <> Value then begin fVertPos := Value; fVertRuler.GripsDir := TGripsDir( ord( Value )); TImageEnView( fOwner).Update(); end; end; {!! TIEViewRulerParams.HorzHeight Declaration property HorzHeight: Integer; Description Specifies the height of the horizontal ruler. Default: 40 Example // Create narrow rulers ImageEnView1.RulerParams.Font.Size := 6; ImageEnView1.RulerParams.HorzHeight := 20; ImageEnView1.RulerParams.VertWidth := 20; ImageEnView1.RulerParams.GripHeight := 10; !!} procedure TIEViewRulerParams.SetHorzHeight(Value: Integer); begin if fHorzHeight <> Value then begin fHorzHeight := Value; TImageEnView( fOwner).Update(); end; end; {!! TIEViewRulerParams.VertWidth Declaration property VertWidth: Integer; Description Specifies the width of the vertical ruler. Default: 40 Example // Create narrow rulers ImageEnView1.RulerParams.Font.Size := 6; ImageEnView1.RulerParams.HorzHeight := 20; ImageEnView1.RulerParams.VertWidth := 20; ImageEnView1.RulerParams.GripHeight := 10; !!} procedure TIEViewRulerParams.SetVertWidth(Value: Integer); begin if fVertWidth <> Value then begin fVertWidth := Value; TImageEnView( fOwner).Update(); end; end; function TIEViewRulerParams.GetHorzRulerRect: TRect; var rLeft, rRight, rTop, rBottom: Integer; begin rLeft := 0; rRight := -1; rTop := 0; rBottom := -1; if VertRulerVisible then begin if fHorzPos = gdUp then begin // Top rTop := 0; rBottom := fHorzHeight; end else begin // Bottom rTop := TImageEnView( fOwner ).ClientHeight - fHorzHeight ; rBottom := TImageEnView( fOwner ).ClientHeight ; end; rLeft := 0; if VertRulerVisible and ( fVertPos = gdLeft ) then rLeft := fVertWidth; rRight := TImageEnView( fOwner ).ClientWidth ; if VertRulerVisible and ( fVertPos <> gdLeft ) then rRight := TImageEnView( fOwner ).ClientWidth - fVertWidth ; end; Result := Rect( rLeft, rTop, rRight, rBottom ); end; function TIEViewRulerParams.GetVertRulerRect: TRect; var rLeft, rRight, rTop, rBottom: Integer; begin rLeft := 0; rRight := -1; rTop := 0; rBottom := -1; if VertRulerVisible then begin if fVertPos = gdLeft then begin // Left rLeft := 0; rRight := fVertWidth; end else begin // Right rLeft := TImageEnView( fOwner ).ClientWidth - fVertWidth ; rRight := TImageEnView( fOwner ).ClientWidth ; end; rTop := 0; if HorzRulerVisible and ( fHorzPos = gdUp ) then rTop := fHorzHeight; rBottom := TImageEnView( fOwner ).ClientHeight ; if HorzRulerVisible and ( fHorzPos = gdDown ) then rBottom := TImageEnView( fOwner ).ClientHeight - fHorzHeight ; end; Result := Rect( rLeft, rTop, rRight, rBottom ); end; function TIEViewRulerParams.RulerAreaLeft: Integer; begin Result := 0; if VertRulerVisible and ( fVertPos = gdLeft ) then Result := fVertWidth; end; function TIEViewRulerParams.RulerAreaRight: Integer; begin Result := 0; if VertRulerVisible and ( fVertPos = gdRight ) then Result := fVertWidth; end; function TIEViewRulerParams.RulerAreaTop: Integer; begin Result := 0; if HorzRulerVisible and ( fHorzPos = gdUp ) then Result := fHorzHeight; end; function TIEViewRulerParams.RulerAreaBottom: Integer; begin Result := 0; if HorzRulerVisible and ( fHorzPos = gdDown ) then Result := fHorzHeight; end; function TIEViewRulerParams.HorzRulerVisible: Boolean; begin Result := rdHorizontal in TImageEnView( fOwner ).ShowRulers; end; function TIEViewRulerParams.VertRulerVisible: Boolean; begin Result := rdVertical in TImageEnView( fOwner ).ShowRulers; end; // Bring grip g into view procedure TIEViewRulerParams.ScrollToHorzGrip(g: Integer); var z: Double; iev: TImageEnView; X: Integer; begin iev := TImageEnView( fOwner ); z := iev.Zoom / 100; X := round( RulerToValueX( fHorzRuler.GripsPos[ g + 1 ], ierbBitmap )); if X < round( iev.ViewX / iev.Zoom * 100 ) then iev.ViewX := round( X * z ) else if X > round(( iev.ViewX + iev.ExtentX ) / iev.Zoom * 100 ) then iev.ViewX := Round(( X - round( iev.ExtentX / iev.Zoom * 100 )) * z ) ; end; // Bring grip g into view procedure TIEViewRulerParams.ScrollToVertGrip(g: Integer); var z: Double; iev: TImageEnView; Y: Integer; begin iev := TImageEnView( fOwner ); z := iev.Zoom / 100; Y := round( RulerToValueY( fVertRuler.GripsPos[ g + 1 ], ierbBitmap )); if Y < round( iev.ViewY / iev.Zoom * 100 ) then iev.ViewY := round( Y * z ) else if Y > round(( iev.ViewY + iev.ExtentY ) / iev.Zoom * 100 ) then iev.ViewY := Round(( Y - round( iev.ExtentY / iev.Zoom * 100 )) * z ) ; end; // Call from TImageEnView.LockUpdate procedure TIEViewRulerParams.LockUpdate(); begin fHorzRuler.LockUpdate(); fVertRuler.LockUpdate(); end; // Call from TImageEnView.UnlockUpdate procedure TIEViewRulerParams.UnlockUpdate(DoUpdate: Boolean = True; DoInvalidate: Boolean = True); begin fHorzRuler.UnlockUpdate( DoUpdate, False ); fVertRuler.UnlockUpdate( DoUpdate, False ); if DoUpdate and ( fHorzRuler.LockUpdateCount <= 0 ) then Update( DoInvalidate ) else if DoInvalidate and ( HorzRulerVisible or VertRulerVisible ) then fOwner.Invalidate(); end; function TIEViewRulerParams.GetOnRulerClick: TRulerClickEvent; begin result := fHorzRuler.fOnRulerClick; end; procedure TIEViewRulerParams.SetOnRulerClick(const Value: TRulerClickEvent); begin fHorzRuler.fOnRulerClick := Value; fVertRuler.fOnRulerClick := Value; end; function TIEViewRulerParams.GetOnRulerGripClick: TRulerGripClickEvent; begin result := fHorzRuler.fOnRulerGripClick; end; procedure TIEViewRulerParams.SetOnRulerGripClick(const Value: TRulerGripClickEvent); begin fHorzRuler.fOnRulerGripClick := Value; fVertRuler.fOnRulerGripClick := Value; end; function TIEViewRulerParams.GetOnRulerGripDblClick: TRulerGripClickEvent; begin result := fHorzRuler.fOnRulerGripDblClick; end; procedure TIEViewRulerParams.SetOnRulerGripDblClick(const Value: TRulerGripClickEvent); begin fHorzRuler.fOnRulerGripDblClick := Value; fVertRuler.fOnRulerGripDblClick := Value; end; function TIEViewRulerParams.GetOnRulerPosChange: TRulerGripPosChangeEvent; begin result := fHorzRuler.fOnRulerGripPosChange; end; procedure TIEViewRulerParams.SetOnRulerPosChange(const Value: TRulerGripPosChangeEvent); begin fHorzRuler.fOnRulerGripPosChange := Value; fVertRuler.fOnRulerGripPosChange := Value; end; end.