Mmscale.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:19k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Tel.: +0351-8012255                   =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 20.01.1998 - 18:00:00 $                                      =}
  24. {========================================================================}
  25. unit MMScale;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29. {$IFDEF WIN32}
  30.     Windows,
  31. {$ELSE}
  32.     WinTypes,
  33.     WinProcs,
  34. {$ENDIF}
  35.     Messages,
  36.     Classes,
  37.     SysUtils,
  38.     Controls,
  39.     ExtCtrls,
  40.     Graphics,
  41.     MMObj,
  42.     MMUtils;
  43. type
  44.     TMMScaleStyle   = (stColor,stLowered,stRaised);
  45.     TMMScaleOrigin  = (soInner,soOuter);
  46. const
  47.     defScaleVisible = True;
  48.     defScaleColor   = clBlack;
  49.     defScaleStyle   = stColor;
  50.     defTickCount    = 11;
  51.     defEnlargeEvery = 5;
  52.     defScaleSize    = 7;
  53.     defScaleOrigin  = soInner;
  54.     defScaleConnect = False;
  55. type
  56.     EMMScaleError   = class(Exception);
  57.     {-- TMMCustomScale ----------------------------------------------------}
  58.     TMMCustomScale  = class(TPersistent)
  59.     private
  60.         FVisible        : Boolean;
  61.         FStartAngle     : Integer;
  62.         FEndAngle       : Integer;
  63.         FColor          : TColor;
  64.         FColor2         : TColor;
  65.         FColor3         : TColor;
  66.         FPoint1         : Integer;
  67.         FPoint2         : Integer;
  68.         FCanvas         : TCanvas;
  69.         FStyle          : TMMScaleStyle;
  70.         FTickCount      : Integer;
  71.         FEnlargeEvery   : Integer;
  72.         FSize           : Integer;
  73.         FOrigin         : TMMScaleOrigin;
  74.         FConnect        : Boolean;
  75.         FOnChange       : TNotifyEvent;
  76.         procedure   SetVisible(Value : Boolean);
  77.         procedure   SetColor(Value : TColor);
  78.         procedure   SetStyle(Value : TMMScaleStyle);
  79.         procedure   SetTickCount(Value : Integer);
  80.         procedure   SetEnlargeEvery(Value : Integer);
  81.         procedure   SetSize(Value : Integer);
  82.         procedure   SetOrigin(Value : TMMScaleOrigin);
  83.         procedure   SetConnect(Value : Boolean);
  84.         function    GetScaleHeight : Integer;
  85.     protected
  86.         procedure   Changed; virtual;
  87.         procedure   DoChange; dynamic;
  88.         procedure   ScaleLine(X1, Y1, X2, Y2: Integer; Color: TColor);
  89.         procedure   ScaleArc(X1,Y1,X2,Y2,StAngle,EnAngle: Integer; Radius: Float);
  90.         procedure   NeedCanvas;
  91.     public
  92.         constructor Create;
  93.         procedure   Assign(Source : TPersistent); override;
  94.         procedure   DrawRect(Canvas : TCanvas; R : TRect; TopLeft : Boolean);
  95.         procedure   DrawElliptic(Canvas : TCanvas; R : TRect);
  96.         property    StartAngle  : Integer read FStartAngle write FStartAngle;
  97.         property    EndAngle    : Integer read FEndAngle write FEndAngle;
  98.         property    Canvas      : TCanvas read FCanvas write FCanvas;
  99.         property    Color2      : TColor read FColor2 write FColor2;
  100.         property    Color3      : TColor read FColor3 write FColor3;
  101.         property    Point1      : Integer read FPoint1 write FPoint1;
  102.         property    Point2      : Integer read FPoint2 write FPoint2;
  103.         property    ScaleHeight : Integer read GetScaleHeight;
  104.         property    OnChange    : TNotifyEvent read FOnChange write FOnChange;
  105.     protected
  106.         property Visible: Boolean read FVisible write SetVisible;
  107.         property Color: TColor read FColor write SetColor;
  108.         property Style: TMMScaleStyle read FStyle write SetStyle;
  109.         property TickCount: Integer read FTickCount write SetTickCount;
  110.         property EnlargeEvery: Integer read FEnlargeEvery write SetEnlargeEvery;
  111.         property Size: Integer read FSize write SetSize;
  112.         property Origin: TMMScaleOrigin read FOrigin write SetOrigin;
  113.         property Connect: Boolean read FConnect write SetConnect;
  114.     end;
  115.     {-- TMMScale --------------------------------------------------------}
  116.     TMMScale    = class(TMMCustomScale)
  117.     published
  118.         property Visible;
  119.         property Color;
  120.         property Style;
  121.         property TickCount;
  122.         property EnlargeEvery;
  123.         property Size;
  124.         property Origin;
  125.         property Connect;
  126.     end;
  127. implementation
  128. {== TMMCustomScale =======================================================}
  129. constructor TMMCustomScale.Create;
  130. begin
  131.     inherited Create;
  132.     FVisible      := defScaleVisible;
  133.     FColor        := defScaleColor;
  134.     FColor2       := defScaleColor;
  135.     FColor3       := defScaleColor;
  136.     FStyle        := defScaleStyle;
  137.     FTickCount    := defTickCount;
  138.     FEnlargeEvery := defEnlargeEvery;
  139.     FSize         := defScaleSize;
  140.     FOrigin       := defScaleOrigin;
  141.     FConnect      := defScaleConnect;
  142. end;
  143. {-- TMMCustomScale -------------------------------------------------------}
  144. procedure   TMMCustomScale.SetVisible(Value: Boolean);
  145. begin
  146.    if FVisible <> Value then
  147.    begin
  148.       FVisible := Value;
  149.       Changed;
  150.    end;
  151. end;
  152. {-- TMMCustomScale -------------------------------------------------------}
  153. procedure TMMCustomScale.SetColor(Value: TColor);
  154. begin
  155.    if FColor <> Value then
  156.    begin
  157.       FColor    := Value;
  158.       FColor2   := Value;
  159.       FColor3   := Value;
  160.       Changed;
  161.    end;
  162. end;
  163. {-- TMMCustomScale -------------------------------------------------------}
  164. procedure TMMCustomScale.SetStyle(Value: TMMScaleStyle);
  165. begin
  166.    if FStyle <> Value then
  167.    begin
  168.       FStyle := Value;
  169.       Changed;
  170.    end;
  171. end;
  172. {-- TMMCustomScale -------------------------------------------------------}
  173. procedure TMMCustomScale.SetTickCount(Value: Integer);
  174. begin
  175.    Value := MinMax(Value, 2, MaxInt);
  176.    if FTickCount <> Value then
  177.    begin
  178.       FTickCount := Value;
  179.       Changed;
  180.    end;
  181. end;
  182. {-- TMMCustomScale -------------------------------------------------------}
  183. procedure TMMCustomScale.SetEnlargeEvery(Value: Integer);
  184. begin
  185.    Value := MinMax(Value, 1, MaxInt);
  186.    if FEnlargeEvery <> Value then
  187.    begin
  188.       FEnlargeEvery := Value;
  189.       Changed;
  190.    end;
  191. end;
  192. {-- TMMCustomScale -------------------------------------------------------}
  193. procedure TMMCustomScale.SetSize(Value: Integer);
  194. begin
  195.    Value := MinMax(Value, 1, MaxInt);
  196.    if FSize <> Value then
  197.    begin
  198.       FSize := Value;
  199.       Changed;
  200.    end;
  201. end;
  202. {-- TMMCustomScale -------------------------------------------------------}
  203. procedure TMMCustomScale.SetOrigin(Value: TMMScaleOrigin);
  204. begin
  205.    if FOrigin <> Value then
  206.    begin
  207.       FOrigin := Value;
  208.       Changed;
  209.    end;
  210. end;
  211. {-- TMMCustomScale -------------------------------------------------------}
  212. procedure TMMCustomScale.SetConnect(Value: Boolean);
  213. begin
  214.    if FConnect <> Value then
  215.    begin
  216.       FConnect := Value;
  217.       Changed;
  218.    end;
  219. end;
  220. {-- TMMCustomScale -------------------------------------------------------}
  221. function TMMCustomScale.GetScaleHeight: Integer;
  222. begin
  223.    Result := FSize;
  224.    if FConnect then
  225.    begin
  226.       Inc(Result);
  227.       if Style <> stColor then Inc(Result);
  228.    end;
  229. end;
  230. {-- TMMCustomScale -------------------------------------------------------}
  231. procedure TMMCustomScale.Changed;
  232. begin
  233.    DoChange;
  234. end;
  235. {-- TMMCustomScale -------------------------------------------------------}
  236. procedure TMMCustomScale.DoChange;
  237. begin
  238.    if Assigned(FOnChange) then FOnChange(Self);
  239. end;
  240. {-- TMMCustomScale -------------------------------------------------------}
  241. procedure TMMCustomScale.Assign(Source: TPersistent);
  242. var
  243.     S: TMMScale;
  244. begin
  245.    if Source is TMMScale then
  246.    begin
  247.       S             := (Source as TMMScale);
  248.       FVisible      := S.FVisible;
  249.       FColor        := S.FColor;
  250.       FStyle        := S.FStyle;
  251.       FTickCount    := S.FTickCount;
  252.       FEnlargeEvery := S.FEnlargeEvery;
  253.       FSize         := S.FSize;
  254.       FOrigin       := S.FOrigin;
  255.       FConnect      := S.FConnect;
  256.       Changed;
  257.     end
  258.     else inherited Assign(Source);
  259. end;
  260. {-------------------------------------------------------------------------}
  261. function RRound(Base, V: Float): LongInt;
  262. begin
  263.    if V >= Base then
  264.       Result := Trunc(V)
  265.    else
  266.       Result := Round(V);
  267. end;
  268. {-------------------------------------------------------------------------}
  269. procedure CalcPoint(OrigX, OrigY, A, R: Float; var X, Y: Integer);
  270. var
  271.    Ang: Float;
  272. begin
  273.    Ang := A / 180 * Pi;
  274.    X   := RRound(OrigX,OrigX + R*Cos(Ang));
  275.    Y   := RRound(OrigY,OrigY - R*Sin(Ang));
  276. end;
  277. {-- TMMCustomScale -------------------------------------------------------}
  278. procedure TMMCustomScale.DrawRect(Canvas: TCanvas; R: TRect; TopLeft: Boolean);
  279. var
  280.    W, H        : Integer;
  281.    Inner       : Boolean;
  282.    Offs, Len   : Float;
  283.    Horz        : Boolean;
  284.    Sz          : Integer;
  285.    i           : Integer;
  286.    Left        : Integer;
  287.    Top         : Integer;
  288.    Right       : Integer;
  289.    Bottom      : Integer;
  290.    MultiColor  : Boolean;
  291.    Len1, Len2  : Float;
  292.    C           : TColor;
  293.    TickSize    : Float;
  294.    function Patch: Integer;
  295.    begin
  296.       if Connect and (Style <> stColor) then
  297.          Result := 1
  298.       else
  299.          Result := 0;
  300.    end;
  301.    procedure HorzLine(X1, Y1, X2: Integer);
  302.    begin
  303.       if MultiColor then
  304.       begin
  305.          ScaleLine(X1,Y1,Trunc(X1+Len1+TickSize),Y1,Color);
  306.          ScaleLine(Trunc(X1+Len1+TickSize),Y1,Trunc(X1+Len2+TickSize),Y1,Color2);
  307.          ScaleLine(Trunc(X1+Len2+TickSize),Y1,X2,Y1,Color3);
  308.       end
  309.       else
  310.         ScaleLine(X1,Y1,X2,Y1,Color);
  311.    end;
  312.    procedure VertLine(X1, Y1, Y2: Integer);
  313.    begin
  314.     if MultiColor then
  315.     begin
  316.        ScaleLine(X1,Y1,X1,Trunc(Y1+Len1+TickSize),Color);
  317.        ScaleLine(X1,Trunc(Y1+Len1+TickSize),X1,Trunc(Y1+Len2+TickSize),Color2);
  318.        ScaleLine(X1,Trunc(Y1+Len2+TickSize),X1,Y2,Color3);
  319.     end
  320.     else
  321.        ScaleLine(X1,Y1,X1,Y2,Color);
  322.    end;
  323. begin
  324.    MultiColor := ((Color2 <> Color) or (Color3 <> Color)) and
  325.                  (Point1 >= 0) and (Point2 >= Point1) and
  326.                  (Point1 <= TickCount) and (Point2 <= TickCount) and
  327.                  (Style = stColor);
  328.    W    := R.Right - R.Left;
  329.    H    := R.Bottom - R.Top;
  330.    Horz := W > H;
  331.    if Horz then
  332.       Len := W
  333.    else
  334.       Len := H;
  335.    if MultiColor then
  336.    begin
  337.       Len1    := Point1/TickCount*Len;
  338.       Len2    := Point2/TickCount*Len;
  339.       TickSize:= 1/TickCount*Len;
  340.    end;
  341.    Inner := Origin = soInner;
  342.    if not TopLeft then
  343.       Inner := not Inner;
  344.    if Connect then
  345.       if Horz then
  346.          if Inner then
  347.             HorzLine(R.Left, R.Bottom-Patch, R.Right + 1)
  348.          else
  349.             HorzLine(R.Left, R.Top-1, R.Right + 1)
  350.       else
  351.          if Inner then
  352.             VertLine(R.Right-1-Patch, R.Top+1, R.Bottom + 1)
  353.          else
  354.             VertLine(R.Left, R.Top+1, R.Bottom + 1);
  355.    for i := 0 to TickCount-1 do
  356.    begin
  357.       Offs := i * (Len/(TickCount-1));
  358.       if Horz then
  359.       begin
  360.          if (i mod EnlargeEvery) = 0 then
  361.              Sz := FSize
  362.          else
  363.              Sz := FSize div 2;
  364.          Left    := Trunc(R.Left + Offs);
  365.          Right   := Left;
  366.          if Inner then
  367.          begin
  368.             Top     := R.Bottom - Sz;
  369.             Bottom  := R.Bottom;
  370.          end
  371.          else
  372.          begin
  373.             Top     := R.Top;
  374.             Bottom  := R.Top + Sz;
  375.          end
  376.       end
  377.       else
  378.       begin
  379.          if (i mod EnlargeEvery) = 0 then
  380.              Sz := FSize
  381.          else
  382.              Sz := FSize div 2;
  383.          Top     := Round(R.Top + Offs);
  384.          Bottom  := Top;
  385.          if Inner then
  386.          begin
  387.             Left    := R.Right - Sz - Patch;
  388.             Right   := R.Right - Patch;
  389.          end
  390.          else
  391.          begin
  392.             Left    := R.Left + Patch;
  393.             Right   := R.Left + Sz + Patch;
  394.          end;
  395.       end;
  396.       if MultiColor then
  397.         if Offs > Len1 then
  398.             if Offs > Len2 then
  399.                 C := Color3
  400.             else
  401.                 C := Color2
  402.         else
  403.             C := Color
  404.       else
  405.         C := Color;
  406.       ScaleLine(Left, Top, Right, Bottom,C);
  407.    end;
  408. end;
  409. {-- TMMCustomScale -------------------------------------------------------}
  410. procedure TMMCustomScale.DrawElliptic(Canvas: TCanvas; R: TRect);
  411. var
  412.    OrigX, OrigY: Float;
  413.    TickAngle   : Float;
  414.    dAngle      : Integer;
  415.    Angle       : Float;
  416.    i           : Integer;
  417.    Radius      : Float;
  418.    RW, RH      : Float;
  419.    ConnRad     : Float;
  420.    ConnRect    : TRect;
  421.    Temp        : Integer;
  422.    procedure DrawAngledLine(Angle: Float; R1, R2: Float);
  423.    var
  424.       X1, Y1: Integer;
  425.       X2, Y2: Integer;
  426.    begin
  427.       CalcPoint(OrigX,OrigY,Angle,R1,X1,Y1);
  428.       CalcPoint(OrigX,OrigY,Angle,R2,X2,Y2);
  429.       ScaleLine(X1, Y1, X2, Y2,Color);
  430.    end;
  431. begin
  432.    RW := (R.Right - R.Left) / 2;
  433.    RH := (R.Bottom - R.Top) / 2;
  434.    OrigX := R.Left + RW;
  435.    OrigY := R.Top + RH;
  436.    if RW < RH then
  437.       Radius  := RW
  438.    else
  439.       Radius  := RH;
  440.    dAngle    := FStartAngle + (360 - EndAngle);
  441.    TickAngle := dAngle / (TickCount-1);
  442.    for i := 0 to TickCount-1 do
  443.    begin
  444.       Angle := FStartAngle - i * TickAngle;
  445.       if (i mod FEnlargeEvery) = 0 then
  446.           DrawAngledLine(Angle, Radius - FSize, Radius)
  447.       else
  448.           if FOrigin = soInner then
  449.              DrawAngledLine(Angle, Radius - FSize, Radius - FSize / 2 + 1)
  450.           else
  451.              DrawAngledLine(Angle, Radius - FSize / 2, Radius);
  452.    end;
  453.    if Connect then
  454.    begin
  455.       if FOrigin = soOuter then
  456.          ConnRad := Radius
  457.       else
  458.          ConnRad := Radius - FSize;
  459.       CalcPoint(OrigX,OrigY,0,ConnRad,ConnRect.Right,Temp);
  460.       CalcPoint(OrigX,OrigY,180,ConnRad,ConnRect.Left,Temp);
  461.       CalcPoint(OrigX,OrigY,90,ConnRad,Temp,ConnRect.Top);
  462.       CalcPoint(OrigX,OrigY,270,ConnRad,Temp,ConnRect.Bottom);
  463.       ScaleArc(ConnRect.Left,ConnRect.Top,ConnRect.Right,ConnRect.Bottom,StartAngle,EndAngle,ConnRad);
  464.    end;
  465. end;
  466. {-- TMMCustomScale -------------------------------------------------------}
  467. procedure TMMCustomScale.NeedCanvas;
  468. begin
  469.    if Canvas = nil then
  470.       { TODO: Should be resource id }
  471.       raise EMMScaleError.Create('Canvas needed for this operation');
  472. end;
  473. {-- TMMCustomScale -------------------------------------------------------}
  474. procedure TMMCustomScale.ScaleLine(X1, Y1, X2, Y2: Integer; Color: TColor);
  475. var
  476.    Slope     : Float;
  477.    dY, dX    : Integer;
  478.    Sign      : Integer;
  479.    YInc, XInc: Integer;
  480. begin
  481.    dY := -(Y2 - Y1);
  482.    dX := X2 - X1;
  483.    NeedCanvas;
  484.    with Canvas do
  485.    if FStyle = stColor then
  486.    begin
  487.       Pen.Color := Color;
  488.       MoveTo(X1,Y1);
  489.       LineTo(X2,Y2);
  490.    end
  491.    else
  492.    begin
  493.       if Style = stLowered then
  494.          Pen.Color := clBlack
  495.       else
  496.          Pen.Color := clWhite;
  497.       MoveTo(X1,Y1);
  498.       LineTo(X2,Y2);
  499.       if Style = stLowered then
  500.          Pen.Color := clWhite
  501.       else
  502.          Pen.Color := clBlack;
  503.       if dX = 0 then
  504.          dX := dY; { Make it work }
  505.       Slope := dY / dX;
  506.       if Slope >= 0 then
  507.          Sign := 1
  508.       else
  509.          Sign := -1;
  510.       XInc := 0;
  511.       YInc := 0;
  512.       if Abs(dY) >= Abs(dX) then
  513.          XInc := Sign
  514.       else
  515.          YInc := 1;
  516.       MoveTo(X1+XInc,Y1+YInc);
  517.       LineTo(X2+XInc,Y2+YInc);
  518.    end;
  519. end;
  520. {-- TMMCustomScale -------------------------------------------------------}
  521. procedure TMMCustomScale.ScaleArc(X1,Y1,X2,Y2,StAngle,EnAngle: Integer; Radius: Float);
  522. var
  523.    XC, YC  : Float;
  524.    X3, Y3  : Integer;
  525.    X4, Y4  : Integer;
  526.    Angle   : Integer;
  527.    Next    : Integer;
  528.    Horz    : Boolean;
  529.    NextLast: Integer;
  530.    function HorzAngle(Angle: Integer; var NextAngle: Integer): Boolean;
  531.    begin
  532.       while Angle >= 360 do Angle := Angle - 360;
  533.       while Angle < 0 do Angle := Angle + 360;
  534.       Result := False;
  535.       if InRange(Angle,46,135) then
  536.       begin
  537.          NextAngle := 45;
  538.          Result    := False;
  539.       end;
  540.       if InRange(Angle,136,225) then
  541.       begin
  542.          NextAngle := 135;
  543.          Result    := True;
  544.       end;
  545.       if InRange(Angle,226,315) then
  546.       begin
  547.          NextAngle := 225;
  548.          Result    := False;
  549.       end;
  550.       if InRange(Angle,316,360) or InRange(Angle,0,45) then
  551.       begin
  552.          NextAngle := 315;
  553.          Result    := True;
  554.       end;
  555.    end;
  556.    procedure SubArc(A1, A2: Integer; Horz: Boolean);
  557.    var
  558.       XA1, YA1, XA2, YA2: Integer;
  559.    begin
  560.       CalcPoint(XC,YC,A2,Radius,XA1,YA1);
  561.       CalcPoint(XC,YC,A1,Radius,XA2,YA2);
  562.       if Horz then
  563.          Canvas.Arc(X1+1,Y1,X2+1,Y2,XA1+1,YA1,XA2+1,YA2)
  564.       else
  565.          Canvas.Arc(X1,Y1+1,X2,Y2+1,XA1,YA1+1,XA2,YA2+1);
  566.    end;
  567. begin
  568.    XC := (X2 - X1) / 2 + X1;
  569.    YC := (Y2 - Y1) / 2 + Y1;
  570.    CalcPoint(XC,YC,StAngle,Radius,X4,Y4);
  571.    CalcPoint(XC,YC,EnAngle,Radius,X3,Y3);
  572.    with Canvas do
  573.    if Style = stColor then
  574.    begin
  575.       Pen.Color := Color;
  576.       Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
  577.    end
  578.    else
  579.    begin
  580.       if Style = stLowered then
  581.          Pen.Color := clBlack
  582.       else
  583.          Pen.Color := clWhite;
  584.       Arc(X1,Y1,X2,Y2,X3,Y3,X4,Y4);
  585.       if Style = stLowered then
  586.          Pen.Color := clWhite
  587.       else
  588.          Pen.Color := clBlack;
  589.       HorzAngle(EnAngle,NextLast);
  590.       Angle  := StAngle;
  591.       while True do
  592.       begin
  593.          Horz := HorzAngle(Angle,Next);
  594.          if (Next = NextLast) or (Next = EnAngle) then
  595.          begin
  596.             SubArc(Angle,EnAngle,Horz);
  597.             Break;
  598.          end
  599.          else SubArc(Angle,Next,Horz);
  600.          Angle   := Next;
  601.       end;
  602.    end;
  603. end;
  604. end.