mirror of
				https://gitlab.com/freepascal.org/lazarus/lazarus.git
				synced 2025-11-04 07:59:43 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			305 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
  *********************************************************************
 | 
						|
  This file is part of the Lazarus Component Library (LCL)
 | 
						|
 | 
						|
  See the file COPYING.modifiedLGPL.txt, included in this distribution,
 | 
						|
  for details about the license.
 | 
						|
  *********************************************************************
 | 
						|
 | 
						|
  Author: H. Page-Clark
 | 
						|
 | 
						|
  Abstract:
 | 
						|
    Show an arrow. Its size, direction, color and shadow can be adjusted.
 | 
						|
}
 | 
						|
 | 
						|
unit Arrow;
 | 
						|
 | 
						|
{$mode objfpc}{$H+}
 | 
						|
 | 
						|
interface
 | 
						|
 | 
						|
uses
 | 
						|
  Classes, types, math, Controls, Graphics, IndustrialBase;
 | 
						|
 | 
						|
type
 | 
						|
 | 
						|
  TArrowType = (atUp, atDown, atLeft, atRight);
 | 
						|
  TShadowType = (stNone, stIn, stOut, stEtchedIn, stEtchedOut, stFilled);
 | 
						|
  TTriPts = (ptA, ptB, ptC);
 | 
						|
  TTrianglePoints = array[TTriPts] of TPoint;
 | 
						|
 | 
						|
  { TArrow }
 | 
						|
 | 
						|
  TArrow = class(TIndustrialBase)
 | 
						|
  private
 | 
						|
    FArrowColor: TColor;
 | 
						|
    FArrowType: TArrowType;
 | 
						|
    FArrowAngle: integer;
 | 
						|
    FShadowType: TShadowType;
 | 
						|
    FShadowColor: TColor;
 | 
						|
    FR: TRect;
 | 
						|
    FT: TTrianglePoints;
 | 
						|
    procedure CalcTrianglePoints;
 | 
						|
    procedure SetArrowAngle(AValue: integer);
 | 
						|
    procedure SetArrowColor(AValue: TColor);
 | 
						|
    procedure SetArrowType(AValue: TArrowType);
 | 
						|
    procedure SetShadowColor(AValue: TColor);
 | 
						|
    procedure SetShadowType(AValue: TShadowType);
 | 
						|
  protected
 | 
						|
    class function GetControlClassDefaultSize: TSize; override;
 | 
						|
    procedure Paint; override;
 | 
						|
  public
 | 
						|
    constructor Create(aOwner: TComponent); override;
 | 
						|
  published
 | 
						|
    property Align;
 | 
						|
    property Anchors;
 | 
						|
    property ArrowColor: TColor read FArrowColor write SetArrowColor default clBlack;
 | 
						|
    property ArrowType: TArrowType read FArrowType write SetArrowType default atLeft;
 | 
						|
    property ArrowPointerAngle: integer read FArrowAngle write SetArrowAngle default 60;
 | 
						|
    property BorderSpacing;
 | 
						|
    property Color;
 | 
						|
    property Constraints;
 | 
						|
    property Hint;
 | 
						|
    property OnChangeBounds;
 | 
						|
    property OnClick;
 | 
						|
    property OnContextPopup;
 | 
						|
    property OnDblClick;
 | 
						|
    property OnDragDrop;
 | 
						|
    property OnDragOver;
 | 
						|
    property OnEndDrag;
 | 
						|
    property OnMouseDown;
 | 
						|
    property OnMouseEnter;
 | 
						|
    property OnMouseLeave;
 | 
						|
    property OnMouseMove;
 | 
						|
    property OnMouseUp;
 | 
						|
    property OnMouseWheel;
 | 
						|
    property OnMouseWheelDown;
 | 
						|
    property OnMouseWheelUp;
 | 
						|
    property OnPaint;
 | 
						|
    property OnResize;
 | 
						|
    property OnStartDrag;
 | 
						|
    property ParentColor;
 | 
						|
    property ParentShowHint;
 | 
						|
    property PopupMenu;
 | 
						|
    property ShadowType: TShadowType read FShadowType write SetShadowType default stEtchedIn;
 | 
						|
    property ShadowColor: TColor read FShadowColor write SetShadowColor default cl3DShadow;
 | 
						|
    property ShowHint;
 | 
						|
    property Visible;
 | 
						|
  end;
 | 
						|
 | 
						|
procedure Register;
 | 
						|
 | 
						|
 | 
						|
implementation
 | 
						|
 | 
						|
const
 | 
						|
  cDefaultControlSize = 20;
 | 
						|
  cMinArrowSize = 8;
 | 
						|
  cMinAngle = 20;
 | 
						|
  cMaxAngle = 160;
 | 
						|
  cShadowColors: array[TShadowType] of TColor =
 | 
						|
    (clWindow, cl3DShadow, cl3DShadow, cl3DHiLight, cl3DHiLight, clBlue{not used});
 | 
						|
  cInnerOffset = 2;
 | 
						|
  cShadowSize = 2; //must be <= cInnerOffset
 | 
						|
 | 
						|
 | 
						|
procedure Register;
 | 
						|
begin
 | 
						|
  RegisterComponents('Misc',[TArrow]);
 | 
						|
end;
 | 
						|
 | 
						|
{ TArrow }
 | 
						|
 | 
						|
procedure TArrow.CalcTrianglePoints;
 | 
						|
var
 | 
						|
  midY, midX: integer;
 | 
						|
  ratioNeed, ratioThis: double;
 | 
						|
  size: TSize;
 | 
						|
begin
 | 
						|
  FR:= ClientRect;
 | 
						|
  InflateRect(FR, -cInnerOffset, -cInnerOffset);
 | 
						|
  Dec(FR.Bottom); // for "filled" shadow
 | 
						|
 | 
						|
  midX:= (FR.Left + FR.Right) div 2;
 | 
						|
  midY:= (FR.Top + FR.Bottom) div 2;
 | 
						|
  size:= Types.Size(FR);
 | 
						|
 | 
						|
  ratioNeed:= 2*Tan(FArrowAngle*pi/(180*2));
 | 
						|
  if FArrowType in [atLeft, atRight] then
 | 
						|
    ratioNeed:= 1/ratioNeed;
 | 
						|
 | 
						|
  ratioThis:= size.cx/size.cy;
 | 
						|
  if ratioThis>=ratioNeed then
 | 
						|
    size.cx:= Trunc(size.cx*ratioNeed/ratioThis)
 | 
						|
  else
 | 
						|
    size.cy:= Trunc(size.cy*ratioThis/ratioNeed);
 | 
						|
 | 
						|
  FR.Top:= midY - size.cy div 2;
 | 
						|
  FR.Bottom:= FR.Top + size.cy;
 | 
						|
  FR.Left:= midX - size.cx div 2;
 | 
						|
  FR.Right:= FR.Left + size.cx;
 | 
						|
 | 
						|
  // angle=90: 1pixel shift appears (reason: float math)
 | 
						|
  // workaround:
 | 
						|
  if FArrowAngle=90 then
 | 
						|
  begin
 | 
						|
    if FArrowType in [atUp, atDown] then
 | 
						|
    begin
 | 
						|
      FR.Left:= midX-size.cy;
 | 
						|
      FR.Right:= midX+size.cy;
 | 
						|
    end
 | 
						|
    else
 | 
						|
    begin
 | 
						|
      FR.Top:= midY-size.cx;
 | 
						|
      FR.Bottom:= midY+size.cx;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
  case FArrowType of
 | 
						|
    atUp: begin
 | 
						|
        FT[ptC] := Point(midX, FR.Top);
 | 
						|
        FT[ptA] := Point(FR.Left, FR.Bottom);
 | 
						|
        FT[ptB] := FR.BottomRight;
 | 
						|
       end;
 | 
						|
    atDown: begin
 | 
						|
        FT[ptA] := FR.TopLeft;
 | 
						|
        FT[ptB] := Point(FR.Right, FR.Top);
 | 
						|
        FT[ptC] := Point(midX, FR.Bottom);
 | 
						|
       end;
 | 
						|
    atLeft: begin
 | 
						|
        FT[ptA] := Point(FR.Right, FR.Top);
 | 
						|
        FT[ptB] := FR.BottomRight;
 | 
						|
        FT[ptC] := Point(FR.Left, midY);
 | 
						|
       end;
 | 
						|
    atRight: begin
 | 
						|
        FT[ptA] := FR.TopLeft;
 | 
						|
        FT[ptB] := Point(FR.Right, midY);
 | 
						|
        FT[ptC] := Point(FR.Left, FR.Bottom);
 | 
						|
       end;
 | 
						|
  end;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TArrow.SetArrowColor(AValue: TColor);
 | 
						|
begin
 | 
						|
  if FArrowColor=AValue then Exit;
 | 
						|
  FArrowColor:=AValue;
 | 
						|
  GraphicChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TArrow.SetArrowType(AValue: TArrowType);
 | 
						|
begin
 | 
						|
  if FArrowType=AValue then Exit;
 | 
						|
  FArrowType:=AValue;
 | 
						|
  GraphicChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TArrow.SetShadowColor(AValue: TColor);
 | 
						|
begin
 | 
						|
  if FShadowColor=AValue then Exit;
 | 
						|
  FShadowColor:= AValue;
 | 
						|
  GraphicChanged;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TArrow.SetArrowAngle(AValue: integer);
 | 
						|
begin
 | 
						|
  if FArrowAngle=AValue then Exit;
 | 
						|
  FArrowAngle:=Max(Min(AValue, cMaxAngle), cMinAngle);
 | 
						|
  GraphicChanged;
 | 
						|
end;
 | 
						|
 | 
						|
 | 
						|
procedure TArrow.SetShadowType(AValue: TShadowType);
 | 
						|
begin
 | 
						|
  if FShadowType=AValue then Exit;
 | 
						|
  FShadowType:=AValue;
 | 
						|
  GraphicChanged;
 | 
						|
end;
 | 
						|
 | 
						|
class function TArrow.GetControlClassDefaultSize: TSize;
 | 
						|
begin
 | 
						|
  Result.cx:=cDefaultControlSize;
 | 
						|
  Result.cy:=cDefaultControlSize;
 | 
						|
end;
 | 
						|
 | 
						|
procedure TArrow.Paint;
 | 
						|
  procedure Offset(var ptA, ptB: TPoint);
 | 
						|
  begin
 | 
						|
    case FArrowType of
 | 
						|
      atUp: begin Inc(ptA.x); Dec(ptA.y); Inc(ptB.x); Dec(ptB.y); end;
 | 
						|
      atDown: begin Inc(ptA.x); Inc(ptA.y); Inc(ptB.x); Inc(ptB.y); end;
 | 
						|
      atLeft: begin Dec(ptA.x); Inc(ptA.y); Dec(ptB.x); Inc(ptB.y); end;
 | 
						|
      atRight: begin Inc(ptA.x); Inc(ptA.y); Inc(ptB.x); Inc(ptB.y); end;
 | 
						|
    end;
 | 
						|
  end;
 | 
						|
 | 
						|
  procedure ShadowLine(p1, p2: TPoint);
 | 
						|
  begin
 | 
						|
    Canvas.Pen.Color:= cShadowColors[FShadowType];
 | 
						|
    Canvas.MoveTo(p1);
 | 
						|
    Canvas.LineTo(p2);
 | 
						|
    Offset(p1, p2);
 | 
						|
    Canvas.Pen.Color:= FShadowColor;
 | 
						|
    Canvas.MoveTo(p1);
 | 
						|
    Canvas.LineTo(p2);
 | 
						|
    if (Height>13) then
 | 
						|
      begin
 | 
						|
        Offset(p1, p2);
 | 
						|
        Canvas.MoveTo(p1);
 | 
						|
        Canvas.LineTo(p2);
 | 
						|
      end;
 | 
						|
  end;
 | 
						|
 | 
						|
  procedure ShadowTriangle;
 | 
						|
  var
 | 
						|
    Pts: TTrianglePoints;
 | 
						|
  begin
 | 
						|
    Pts:= FT;
 | 
						|
    Inc(Pts[ptA].x, cShadowSize);
 | 
						|
    Inc(Pts[ptA].y, cShadowSize);
 | 
						|
    Inc(Pts[ptB].x, cShadowSize);
 | 
						|
    Inc(Pts[ptB].y, cShadowSize);
 | 
						|
    Inc(Pts[ptC].x, cShadowSize);
 | 
						|
    Inc(Pts[ptC].y, cShadowSize);
 | 
						|
    Canvas.Pen.Color:= FShadowColor;
 | 
						|
    Canvas.Brush.Color:= FShadowColor;
 | 
						|
    Canvas.Polygon(Pts);
 | 
						|
  end;
 | 
						|
 | 
						|
begin
 | 
						|
  CalcTrianglePoints;
 | 
						|
 | 
						|
  Canvas.AntialiasingMode := AntiAliasingMode;
 | 
						|
  // Paint background
 | 
						|
  Canvas.Brush.Color := Color;
 | 
						|
  Canvas.FillRect(ClientRect);
 | 
						|
 | 
						|
  // Paint shadow area
 | 
						|
  if (FShadowType=stFilled) then
 | 
						|
    ShadowTriangle;
 | 
						|
 | 
						|
  // Paint arrow
 | 
						|
  Canvas.Pen.Color:= FArrowColor;
 | 
						|
  Canvas.Brush.Color:= FArrowColor;
 | 
						|
  Canvas.Polygon(FT);
 | 
						|
 | 
						|
  if not (FShadowType in [stNone, stFilled]) then
 | 
						|
    ShadowLine(FT[ptB], FT[ptC]);
 | 
						|
 | 
						|
  inherited Paint;
 | 
						|
end;
 | 
						|
 | 
						|
constructor TArrow.Create(aOwner: TComponent);
 | 
						|
begin
 | 
						|
  inherited Create(aOwner);
 | 
						|
  Constraints.MinHeight:= cMinArrowSize;
 | 
						|
  Constraints.MinWidth:= cMinArrowSize;
 | 
						|
  FArrowType:= atLeft; // set defaults to match TArrow component
 | 
						|
  FArrowAngle:= 60; // angle of equal side triangle
 | 
						|
  FShadowType:= stEtchedIn;
 | 
						|
  FShadowColor:= cl3DShadow;
 | 
						|
  FArrowColor:= clBlack;
 | 
						|
end;
 | 
						|
 | 
						|
end.
 | 
						|
 |