Files
lazarus-ccr/components/gradcontrols/src/ugradbtn.pas

1220 lines
31 KiB
ObjectPascal
Raw Normal View History

{
@name GradButton
@author Eugen Bolz
@lastchange 21.07.2008
@version 1.4
@thx to http://www.delphipraxis.net/topic67805_farbverlauf+berechnen.html
@license http://creativecommons.org/licenses/LGPL/2.1/
@wiki http://wiki.lazarus.freepascal.org/TGradButton
}
unit ugradbtn;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Controls, graphics, LCLType,LResources,
LCLIntf ,Buttons, urotatebitmap, types;
type
TGradButton = class;
TTextAlignment = (taLeftJustify, taRightJustify, taCenter);
TBorderSide = (bsTopLine, bsBottomLine, bsLeftLine, bsRightLine);
TBorderSides = set of TBorderSide;
TGradientType = (gtHorizontal,gtVertical);
TGBBackgroundPaintEvent = procedure(Sender: TGradButton;
TargetCanvas: TCanvas; R: TRect; BState : TButtonState) of object;
{ TGradButton }
TGradButton = class(TCustomControl)
private
FAutoHeight: Boolean;
FAutoHeightBorderSpacing: Integer;
FAutoWidthBorderSpacing: Integer;
FOnBorderBackgroundPaint: TGBBackgroundPaintEvent;
FRotateDirection : TRotateDirection;
FTextAlignment : TTextAlignment;
FButtonLayout: TButtonLayout;
FTextPoint, FGlyphPoint : TPoint;
FTextSize, FGlyphSize : TSize;
FBackground, bm,
FNormalBackgroundCache, FHotBackgroundCache,
FDownBackgroundCache, FDisabledBackgroundCache : TBitmap;
FRotatedGlyph : TRotatedGlyph;
FTextGlyphSpacing: Integer;
FGradientType : TGradientType;
FShowFocusBorder, FOnlyBackground,
FAutoWidth, FShowGlyph, FEnabled, FFocused : Boolean;
FBackgroundRect: TRect;
FBorderSides: TBorderSides;
FOnNormalBackgroundPaint, FOnHotBackgroundPaint,
FOnDownBackgroundPaint, FOnDisabledBackgroundPaint : TGBBackgroundPaintEvent;
procedure PaintGradient(TrgCanvas: TCanvas; pr : TRect);
procedure UpdateBackground;
procedure PaintBackground(AState: TButtonState; TrgBitmap: TBitmap);
protected
FState, FOldState: TButtonState;
FNormalBlend,FOverBlend : Extended;
FBaseColor, FNormalBlendColor, FOverBlendColor, FDisabledColor,
FBackgroundColor, FGlyphBackgroundColor, FClickColor: TColor;
FOwnerBackgroundDraw : Boolean;
procedure SetAutoHeight(const AValue: Boolean); virtual;
procedure SetAutoHeightBorderSpacing(const AValue: Integer); virtual;
procedure SetAutoWidthBorderSpacing(const AValue: Integer); virtual;
procedure InvPaint(StateCheck:Boolean=false);
procedure FontChanged(Sender: TObject); override;
procedure GlyphChanged(Sender: TObject); virtual;
procedure GetBackgroundRect(var TheRect : TRect); virtual;
procedure GetContentRect(var TheRect: TRect); virtual;
function GetGlyph : TBitmap;
procedure SetEnabled(Value: Boolean); override;
procedure SetAutoWidth(const Value : Boolean); virtual;
procedure SetNormalBlend(const Value: Extended); virtual;
procedure SetOverBlend(const Value: Extended); virtual;
procedure SetBaseColor(const Value: TColor); virtual;
procedure SetNormalBlendColor(const Value: TColor); virtual;
procedure SetOverBlendColor(const Value: TColor); virtual;
procedure SetBackgroundColor(const Value: TColor); virtual;
procedure SetBorderSides(const Value: TBorderSides); virtual;
procedure SetOwnerBackgroundDraw(const Value: Boolean); virtual;
procedure SetGradientType(const Value: TGradientType); virtual;
procedure SetRotateDirection(const Value: TRotateDirection); virtual;
procedure SetShowGlyph(const Value: Boolean); virtual;
procedure SetGlyphBackgroundColor(const Value: TColor); virtual;
procedure SetTextAlignment(const Value: TTextAlignment); virtual;
procedure SetTextGlyphSpacing(const Value: Integer); virtual;
procedure SetButtonLayout(const Value: TButtonLayout); virtual;
procedure SetClickColor(const Value: TColor); virtual;
procedure SetDisabledColor(const Value: TColor); virtual;
procedure SetName(const Value: TComponentName); override;
procedure SetShowFocusBorder(const Value: Boolean); virtual;
procedure SetGlyph(const Value: TBitmap); virtual;
procedure TextChanged; override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
//procedure CreateParams(var Params: TCreateParams); override;
procedure Paint; override;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState;
X, Y: Integer); override;
procedure DoEnter; override;
procedure DoExit; override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
function GetBackground : TCanvas;
procedure Click; override;
procedure Resize; override;
function Focused: Boolean; override;
procedure UpdateButton;
procedure UpdatePositions;
function GetAutoWidth : Integer;
function GetAutoHeight : Integer;
published
property Action;
property Anchors;
property Align;
property BorderSpacing;
property Caption;
property Enabled;
property PopupMenu;
property Font;
property Visible;
property OnClick;
property OnMouseDown;
property OnMouseEnter;
property OnMouseLeave;
property OnMouseMove;
property OnMouseUp;
property OnPaint;
property OnResize;
property OnStartDrag;
property DragMode;
property DragKind;
property DragCursor;
property TabOrder;
property TabStop;
property NormalBlend : Extended read FNormalBlend write SetNormalBlend;
property OverBlend : Extended read FOverBlend write SetOverBlend;
property BaseColor: TColor read FBaseColor write SetBaseColor;
property Color: TColor read FBaseColor write SetBaseColor;
property NormalBlendColor: TColor read FNormalBlendColor write SetNormalBlendColor;
property OverBlendColor: TColor read FOverBlendColor write SetOverBlendColor;
property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor;
property AutoWidth : Boolean read FAutoWidth write SetAutoWidth default false;
property AutoHeight: Boolean read FAutoHeight write SetAutoHeight default false;
property BorderSides : TBorderSides read FBorderSides write SetBorderSides default [bsTopLine,bsBottomLine,bsLeftLine,bsRightLine];
property GradientType : TGradientType read FGradientType write SetGradientType default gtHorizontal;
property ShowFocusBorder : Boolean read FShowFocusBorder write SetShowFocusBorder;
property RotateDirection : TRotateDirection read FRotateDirection write SetRotateDirection default rdNormal;
property ButtonLayout : TButtonLayout read FButtonLayout write SetButtonLayout default blGlyphLeft;
property Glyph : TBitmap read GetGlyph write SetGlyph;
property ShowGlyph : Boolean read FShowGlyph write SetShowGlyph;
property GlyphBackgroundColor : TColor read FGlyphBackgroundColor write SetGlyphBackgroundColor;
property TextAlignment : TTextAlignment read FTextAlignment write SetTextAlignment default taCenter;
property TextGlyphSpacing : Integer read FTextGlyphSpacing write SetTextGlyphSpacing default 2;
property ClickColor : TColor read FClickColor write SetClickColor;
property DisabledColor : TColor read FDisabledColor write SetDisabledColor default clGray;
property OwnerBackgroundDraw : Boolean read FOwnerBackgroundDraw write SetOwnerBackgroundDraw;
property AutoWidthBorderSpacing : Integer read FAutoWidthBorderSpacing write SetAutoWidthBorderSpacing;
property AutoHeightBorderSpacing : Integer read FAutoHeightBorderSpacing write SetAutoHeightBorderSpacing;
property OnNormalBackgroundPaint : TGBBackgroundPaintEvent read FOnNormalBackgroundPaint write FOnNormalBackgroundPaint;
property OnHotBackgroundPaint : TGBBackgroundPaintEvent read FOnHotBackgroundPaint write FOnHotBackgroundPaint;
property OnDownBackgroundPaint : TGBBackgroundPaintEvent read FOnDownBackgroundPaint write FOnDownBackgroundPaint;
property OnDisabledBackgroundPaint : TGBBackgroundPaintEvent read FOnDisabledBackgroundPaint write FOnDisabledBackgroundPaint;
property OnBorderBackgroundPaint : TGBBackgroundPaintEvent read FOnBorderBackgroundPaint write FOnBorderBackgroundPaint;
end;
function ColorBetween(C1, C2 : TColor; blend:Extended):TColor;
function ColorsBetween(colors:array of TColor; blend:Extended):TColor;
function AlignItem(ItemLength, AreaLength,Spacing: Integer; ATextAlignment: TTextAlignment):Integer;
procedure Register;
implementation
uses
LCLProc, math;
function AlignItem(ItemLength, AreaLength,Spacing: Integer; ATextAlignment: TTextAlignment):Integer;
begin
case ATextAlignment of
taLeftJustify : Result := Spacing;
taRightJustify: begin
Result := AreaLength-ItemLength-Spacing;
end;
taCenter : begin
Result := (AreaLength div 2)-(ItemLength div 2);
end;
end;
end;
procedure TGradButton.SetShowFocusBorder(const Value: Boolean);
begin
FShowFocusBorder:=Value;
InvPaint;
end;
procedure TGradButton.SetGlyph(const Value: TBitmap);
begin
FRotatedGlyph.Bitmap := Value;
end;
procedure TGradButton.TextChanged;
begin
inherited TextChanged;
if FAutoWidth then
UpdateButton
else
UpdatePositions;
InvPaint;
end;
procedure TGradButton.SetName(const Value: TComponentName);
begin
if (Caption='') OR (Caption=Name) then
begin
Caption:=Value;
end;
inherited;
end;
function TGradButton.Focused: Boolean;
begin
FFocused:=FFocused OR (Inherited Focused);
Result := FFocused;
end;
procedure TGradButton.SetAutoWidth(const Value : Boolean);
begin
if FAutoWidth = Value then
Exit;
FAutoWidth := Value;
UpdateButton;
end;
procedure TGradButton.Resize;
begin
inherited;
if (HasParent) then
begin
if FAutoWidth then
UpdateButton
else begin
UpdatePositions;
UpdateBackground;
end;
end;
end;
procedure TGradButton.UpdatePositions;
var
tempTS,tempGS : TSize;
p,t,midx, midy, textmidx, textmidy,
groupwidth, groupheight, AreaWidth, AreaHeight :Integer;
tempBL : TButtonLayout;
begin
GetContentRect(FBackgroundRect);
AreaWidth := FBackgroundRect.Right-FBackgroundRect.Left;
AreaHeight := FBackgroundRect.Bottom-FBackgroundRect.Top;
tempGS.cx:=0;
tempGS.cy:=0;
if FShowGlyph and not FRotatedGlyph.Empty then
begin
tempGS.cx:=FRotatedGlyph.Width;
tempGS.cy:=FRotatedGlyph.Height;
end;
tempTS := bm.Canvas.TextExtent(Caption);
if FRotateDirection <> rdNormal then
begin
FTextSize.cx := tempTS.cy;
FTextSize.cy := tempTS.cx;
tempTS := FTextSize;
end
else
FTextSize := tempTS;
tempBL := FButtonLayout;
if FShowGlyph and not FRotatedGlyph.Empty then begin
case tempBL of
blGlyphLeft: begin
FGlyphPoint.x := AlignItem(tempGS.cx+FTextGlyphSpacing+tempTS.cx,AreaWidth,4,FTextAlignment);
FGlyphPoint.y := AlignItem(tempGS.cy,AreaHeight,0, taCenter);
FTextPoint.x := FGlyphPoint.x+tempGS.cx+FTextGlyphSpacing;
FTextPoint.y := AlignItem(tempTS.cy,AreaHeight,0, taCenter);
end;
blGlyphRight: begin
//Glyph Right, Text Left
FTextPoint.x := AlignItem(tempTS.cx+FTextGlyphSpacing+tempGS.cx,AreaWidth,4, FTextAlignment);
FTextPoint.y := AlignItem(tempTS.cy,AreaHeight,0, taCenter);
FGlyphPoint.x := FTextPoint.x+tempTS.cx+FTextGlyphSpacing;
FGlyphPoint.y := AlignItem(tempGS.cy,AreaHeight,0, taCenter);
end;
blGlyphTop: begin
//Glyph Top, Text Bottom
FGlyphPoint.x := AlignItem(tempGS.cx,AreaWidth, 0, FTextAlignment);
FTextPoint.x := AlignItem(tempTS.cx, AreaWidth, 0, FTextAlignment);
FGlyphPoint.y := AlignItem(tempGS.cy+FTextGlyphSpacing+tempTS.cy, AreaHeight, 4, taCenter);
FTextPoint.y := FGlyphPoint.y+tempGS.cy+FTextGlyphSpacing;
end;
blGlyphBottom: begin
//Glyph Bottom, Text Top
FGlyphPoint.x := AlignItem(tempGS.cx,AreaWidth, 0, FTextAlignment);
FTextPoint.x := AlignItem(tempTS.cx, AreaWidth, 0, FTextAlignment);
FTextPoint.y := AlignItem(tempGS.cy+FTextGlyphSpacing+tempTS.cy, AreaHeight, 4, taCenter);
FGlyphPoint.y := FTextPoint.y+tempTS.cy+FTextGlyphSpacing;
end;
end;
end else begin
FGlyphPoint.x := 0;
FGlyphPoint.y := 0;
FTextPoint.x := AlignItem(tempTS.cx,AreaWidth,4, FTextAlignment);
FTextPoint.y := AlignItem(tempTS.cy,AreaHeight,0, taCenter);
end;
//WritePoints([TP^, GP^]);
{TP^.x := TP^.x + p;
TP^.y := TP^.y + p;
GP^.x := GP^.x + p;
GP^.y := GP^.y + p; }
FTextPoint.x := FTextPoint.x+FBackgroundRect.Left;
FTextPoint.y := FTextPoint.y+FBackgroundRect.Top;
FGlyphPoint.x := FGlyphPoint.x+FBackgroundRect.Left;
FGlyphPoint.y := FGlyphPoint.y+FBackgroundRect.Top;
{$IFDEF DEBUGGRADBUTTON}
WriteLn('Text');
WritePoint(FTextPoint);
WriteLn('Glyph');
WritePoint(FGlyphPoint);
{$ENDIF}
FGlyphSize:=tempGS;
end;
function TGradButton.GetAutoWidth: Integer;
begin
if FShowGlyph then begin
if FButtonLayout in [blGlyphLeft,blGlyphRight] then
Result := FTextSize.cx+ FRotatedGlyph.Width+FTextGlyphSpacing+FAutoWidthBorderSpacing
else
Result := Max(FTextSize.cx,FRotatedGlyph.Width)+FAutoWidthBorderSpacing;
end else begin
Result := FTextSize.cx+FAutoWidthBorderSpacing;
end;
end;
function TGradButton.GetAutoHeight: Integer;
begin
if FShowGlyph then begin
if FButtonLayout in [blGlyphTop,blGlyphBottom] then
Result := FTextSize.cy+ FRotatedGlyph.Height+FTextGlyphSpacing+FAutoHeightBorderSpacing
else
Result := Max(FTextSize.cy,FRotatedGlyph.Height)+FAutoHeightBorderSpacing;
end else begin
Result := FTextSize.cy+FAutoHeightBorderSpacing;
end;
end;
procedure TGradButton.PaintBackground(AState: TButtonState; TrgBitmap: TBitmap);
var
FTempState : TButtonState;
FOnTemp : TGBBackgroundPaintEvent;
begin
FTempState:=FState;
GetBackgroundRect(FBackgroundRect);
with TrgBitmap do
begin
Canvas.Font.Color := Self.Font.Color;
Canvas.Font := Self.Font;
Width := Self.Width;
Height := Self.Height;
Canvas.Brush.Color:=clWhite;
Canvas.FillRect(0, 0, Width, Height);
if Self.Parent is TGradButton then
begin
bm.Canvas.CopyRect(Rect(0, 0, Width, Height), (Self.Parent as TGradButton).GetBackground,
Rect(Left,Top,Left+Width,Top+Height));
end else begin
Canvas.Brush.Color:=FBackgroundColor;
Canvas.FillRect(0 , 0, Width, Height);
end;
if FOwnerBackgroundDraw AND (FOnBorderBackgroundPaint<>nil) then
begin
FOnBorderBackgroundPaint(Self, Canvas, FBackgroundRect, AState);
end else begin
//Top
if (bsTopLine in BorderSides) then
begin
Canvas.Pen.Color:=clBlack;
Canvas.Line(FBackgroundRect.Left,0,FBackgroundRect.Right,0);
Canvas.Pen.Color:=clWhite;
Canvas.Line(FBackgroundRect.Left,1,FBackgroundRect.Right,1);
end;
//Left
if (bsLeftLine in BorderSides) then
begin
Canvas.Pen.Color:=clBlack;
Canvas.Line(0,FBackgroundRect.Top,0,FBackgroundRect.Bottom);
Canvas.Pen.Color:=clWhite;
Canvas.Line(1,FBackgroundRect.Top,1,FBackgroundRect.Bottom);
end;
//Right
if (bsRightLine in BorderSides) then
begin
Canvas.Pen.Color:=clBlack;
Canvas.Line(Width-1,FBackgroundRect.Top,Width-1,FBackgroundRect.Bottom);
Canvas.Pen.Color:=clWhite;
Canvas.Line(Width-2,FBackgroundRect.Top,Width-2,FBackgroundRect.Bottom);
end;
//Bottom
if (bsBottomLine in BorderSides) then
begin
Canvas.Pen.Color:=clBlack;
Canvas.Line(FBackgroundRect.Left,Height-1,FBackgroundRect.Right,Height-1);
Canvas.Pen.Color:=clWhite;
Canvas.Line(FBackgroundRect.Left,Height-2,FBackgroundRect.Right,Height-2);
end;
//TopLeft
if (bsTopLine in BorderSides) AND (bsLeftLine in BorderSides) then
Canvas.Pixels[1,1]:=clBlack;
//TopRight
if (bsTopLine in BorderSides) AND (bsRightLine in BorderSides) then
Canvas.Pixels[Width-2,1] := clBlack;
//BottomLeft
if (bsBottomLine in BorderSides) AND (bsLeftLine in BorderSides) then
Canvas.Pixels[1, Height-2]:=clBlack;
//BottomRight
if (bsBottomLine in BorderSides) AND (bsRightLine in BorderSides) then
Canvas.Pixels[Width-2,Height-2]:=clBlack;
end;
FState:=AState;
if FOwnerBackgroundDraw then
begin
if not FEnabled then
FState := bsDisabled;
case FState of
bsUp: FOnTemp := FOnNormalBackgroundPaint;
bsHot:FOnTemp := FOnHotBackgroundPaint;
bsDown: FOnTemp := FOnDownBackgroundPaint;
bsDisabled: FOnTemp := FOnDisabledBackgroundPaint;
end;
if FOnTemp <> nil then
begin
FOnTemp(Self, Canvas, FBackgroundRect, FState);
end;
end else begin
PaintGradient(Canvas, FBackgroundRect);
end;
end;
FState:=FTempState;
end;
procedure TGradButton.UpdateBackground;
var
FTempState : TButtonState;
begin
FTempState:= FState;
FEnabled:=true;
PaintBackground(bsUp,FNormalBackgroundCache);
PaintBackground(bsHot, FHotBackgroundCache);
PaintBackground(bsDown, FDownBackgroundCache);
FEnabled:=false;
PaintBackground(bsUp, FDisabledBackgroundCache);
FEnabled:=Enabled;
FState:=FTempState;
InvPaint;
end;
procedure TGradButton.GetBackgroundRect(var TheRect: TRect);
begin
TheRect := Rect(0,0,Width,Height);
//Top
if (bsTopLine in BorderSides) then
begin
TheRect.Top := 2;
end else
TheRect.Top := 0;
//Left
if (bsLeftLine in BorderSides) then
begin
TheRect.Left := 2;
end else
TheRect.Left := 0;
//Right
if (bsRightLine in BorderSides) then
begin
TheRect.Right := TheRect.Right-{$IFDEF windows}2{$ELSE}3{$ENDIF};
end;
//Bottom
if (bsBottomLine in BorderSides) then
begin
TheRect.Bottom := TheRect.Bottom - 2;
end;
end;
procedure TGradButton.GetContentRect(var TheRect: TRect);
begin
TheRect := Rect(0,0,Width,Height);
//Top
if (bsTopLine in BorderSides) then
begin
TheRect.Top := 2;
end else
TheRect.Top := 0;
//Left
if (bsLeftLine in BorderSides) then
begin
TheRect.Left := 2;
end else
TheRect.Left := 0;
//Right
if (bsRightLine in BorderSides) then
begin
TheRect.Right := TheRect.Right-{$IFDEF windows}2{$ELSE}3{$ENDIF};
end;
//Bottom
if (bsBottomLine in BorderSides) then
begin
TheRect.Bottom := TheRect.Bottom - 2;
end;
end;
function TGradButton.GetGlyph : TBitmap;
begin
Result := FRotatedGlyph.Bitmap;
end;
procedure TGradButton.SetDisabledColor(const Value: TColor);
begin
FDisabledColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetClickColor(const Value: TColor);
begin
FClickColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetButtonLayout(const Value: TButtonLayout);
begin
FButtonLayout:=Value;
UpdatePositions;
InvPaint;
end;
procedure TGradButton.SetGlyphBackgroundColor(const Value: TColor);
begin
FGlyphBackgroundColor:=Value;
//todo: see the desired behavior of GlyphBackgroundColor
//FRotatedGlyph.TransparentColor:=Value;
InvPaint;
end;
procedure TGradButton.SetTextAlignment(const Value: TTextAlignment);
begin
FTextAlignment:=Value;
UpdatePositions;
InvPaint;
end;
procedure TGradButton.SetTextGlyphSpacing(const Value: Integer);
begin
FTextGlyphSpacing:=Value;
UpdatePositions;
InvPaint;
end;
procedure TGradButton.SetEnabled(Value: Boolean);
begin
Inherited;
FEnabled:=Value;
InvPaint;
end;
procedure TGradButton.UpdateButton;
begin
if FAutoWidth then Width := GetAutoWidth;
if FAutoHeight then Height := GetAutoHeight;
UpdateBackground;
UpdatePositions;
end;
procedure TGradButton.SetShowGlyph(const Value: Boolean);
begin
if (FShowGlyph <> Value) AND FRotatedGlyph.IsBitmapStored then
begin
FShowGlyph:=Value;
UpdatePositions;
InvPaint;
end;
end;
procedure TGradButton.SetRotateDirection(const Value: TRotateDirection);
begin
if FRotateDirection = Value then
Exit;
FRotateDirection:=Value;
//Rotate and Cache
FRotatedGlyph.Direction:=FRotateDirection;
UpdatePositions;
UpdateButton;
InvPaint;
end;
procedure TGradButton.SetBackgroundColor(const Value: TColor);
begin
FBackgroundColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetGradientType(const Value: TGradientType);
begin
if FGradientType = Value then
Exit;
FGradientType:=Value;
UpdateBackground;
InvPaint;
end;
function TGradButton.GetBackground : TCanvas;
begin
FOnlyBackground:=true;
Paint;
FOnlyBackground:=false;
Result := FBackground.Canvas;
end;
procedure TGradButton.PaintGradient(TrgCanvas: TCanvas; pr : TRect);
var
r : Integer;
t1,t2,t3 : TColor;
begin
case FState of
bsHot,bsDown : begin
t3 := FOverBlendColor;
end;
else begin
t3 := FNormalBlendColor;
end;
end;
if FState = bsDown then begin
t1 := FClickColor;
end else if FEnabled then begin
t1 := FBaseColor;
end else begin
t1 := FDisabledColor;
t3 := FNormalBlendColor;
end;
t2 := ColorBetween(t1, t3, FNormalBlend);
if GradientType = gtHorizontal then
begin
if FState = bsDown then
begin
for r := (pr.Bottom)-1 downto pr.Top do
begin
if (r > (pr.Bottom/2)) then
begin
TrgCanvas.Pen.Color:= ColorBetween(t1,t2,FOverBlend);
end else begin
TrgCanvas.Pen.Color := ColorsBetween([t1,t2], 1.0-(r / pr.Bottom));
end;
TrgCanvas.Line(pr.Left,r,pr.Right,r);
end;
end else
for r := (pr.Bottom)-1 downto pr.Top do
begin
if (r <= (pr.Bottom/2)) then
begin
//WriteLn('R: ', r, ' M: ', Trunc(pr.Bottom/2));
TrgCanvas.Pen.Color:= ColorBetween(t1,t2,FOverBlend);
end else begin
TrgCanvas.Pen.Color := ColorsBetween([t1,t2], r / pr.Bottom);
end;
TrgCanvas.Line(pr.Left,r,pr.Right,r);
end;
end else begin
if FState = bsDown then
begin
for r := (pr.Right)-1 downto pr.Left do
begin
if (r >= (pr.Right/2)) then
begin
TrgCanvas.Pen.Color:= ColorBetween(t1,t2,FOverBlend);
end else begin
TrgCanvas.Pen.Color := ColorsBetween([t1,t2], 1.0-(r / pr.Right));
end;
TrgCanvas.Line(r,pr.Top,r,pr.Bottom);
end;
end else
for r := (pr.Right)-1 downto pr.Left do
begin
if (r <= (pr.Right/2)) then
begin
TrgCanvas.Pen.Color:= ColorBetween(t1,t2,FOverBlend);
end else begin
TrgCanvas.Pen.Color := ColorsBetween([t1,t2], r / pr.Right);
end;
TrgCanvas.Line(r,pr.Top,r,pr.Bottom);
end;
end;
end;
procedure TGradButton.SetAutoHeight(const AValue: Boolean);
begin
if FAutoHeight=AValue then exit;
FAutoHeight:=AValue;
UpdateButton;
end;
procedure TGradButton.SetAutoHeightBorderSpacing(const AValue: Integer);
begin
if FAutoHeightBorderSpacing=AValue then exit;
FAutoHeightBorderSpacing:=AValue;
UpdateButton;
end;
procedure TGradButton.SetAutoWidthBorderSpacing(const AValue: Integer);
begin
if FAutoWidthBorderSpacing=AValue then exit;
FAutoWidthBorderSpacing:=AValue;
UpdateButton;
end;
constructor TGradButton.Create(AOwner: TComponent);
begin
inherited;
Width:=80;
Height:=25;
FAutoWidthBorderSpacing:=15;
FAutoHeightBorderSpacing:=15;
FNormalBlend:=0.5;
FOverBlend:=0.653;
FBaseColor:=clBlue;
FNormalBlendColor:=clWhite;
FOverBlendColor:=clSilver;
FBackgroundColor:=clBtnFace;
FClickColor:=clBlue;
FDisabledColor:=clGray;
FEnabled:=true;
FAutoWidth:=false;
FAutoHeight:=false;
FOwnerBackgroundDraw := false;
FOnlyBackground:=false;
FShowFocusBorder:=true;
FRotateDirection:=rdNormal;
FTextAlignment:=taCenter;
FTextGlyphSpacing := 2;
TabStop:=true;
ControlStyle := ControlStyle + [csAcceptsControls];
DoubleBuffered:=true;
FBackground := TBitmap.Create;
with FBackground do
begin
Width:=Self.Width;
Height:=Self.Height;
end;
FRotatedGlyph := TRotatedGlyph.Create;
FRotatedGlyph.OnChange := @GlyphChanged;
FButtonLayout:=blGlyphLeft;
FGlyphBackgroundColor:=clWhite;
FNormalBackgroundCache := TBitmap.Create;
FHotBackgroundCache := TBitmap.Create;
FDownBackgroundCache := TBitmap.Create;
FDisabledBackgroundCache := TBitmap.Create;
FBorderSides:=[bsTopLine,bsBottomLine,bsLeftLine,bsRightLine];
bm := TBitmap.Create;
bm.Canvas.Brush.Style := bsClear;
UpdateBackground;
Font.Color:=clWhite;
end;
destructor TGradButton.Destroy;
begin
//DebugLn('bm.Free');
bm.Free;
//DebugLn('FRotatedGlyph.Free');
FRotatedGlyph.Free;
//DebugLn('FBackground.Free');
FBackground.Free;
//DebugLn('FNormalBackgroundCache.Free');
FNormalBackgroundCache.Free;
//DebugLn('FHotBackgroundCache.Free');
FHotBackgroundCache.Free;
//DebugLn('FDownBackgroundCache.Free');
FDownBackgroundCache.Free;
//DebugLn('FDisabledBackgroundCache.Free');
FDisabledBackgroundCache.Free;
inherited;
end;
procedure TGradButton.SetBorderSides(const Value: TBorderSides);
begin
FBorderSides:=Value;
UpdateBackground;
UpdatePositions;
InvPaint;
end;
procedure TGradButton.SetOwnerBackgroundDraw(const Value: Boolean);
begin
FOwnerBackgroundDraw:=Value;
if Value then
begin
UpdateBackground;
InvPaint;
end;
end;
procedure TGradButton.SetNormalBlend(const Value: Extended);
begin
FNormalBlend:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetOverBlend(const Value: Extended);
begin
FOverBlend:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetBaseColor(const Value: TColor);
begin
if FBaseColor = FClickColor then FClickColor := Value;
FBaseColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetNormalBlendColor(const Value: TColor);
begin
FNormalBlendColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.SetOverBlendColor(const Value: TColor);
begin
FOverBlendColor:=Value;
UpdateBackground;
InvPaint;
end;
procedure TGradButton.InvPaint(StateCheck:Boolean);
var
doIt : Boolean;
begin
doIt := true;
if StateCheck then
begin
doIt := (FOldState<>FState);
end;
if doIt then
begin
FOldState:=FState;
Invalidate;
end;
end;
procedure TGradButton.FontChanged(Sender: TObject);
begin
inherited FontChanged(Sender);
bm.Canvas.Font := Font;
UpdatePositions;
end;
procedure TGradButton.GlyphChanged(Sender: TObject);
begin
UpdatePositions;
Invalidate;
end;
procedure TGradButton.DoEnter;
begin
FState:=bsHot;
FFocused:=true;
InvPaint;
inherited;
end;
procedure TGradButton.KeyUp(var Key: Word; Shift: TShiftState);
begin
if Key in [VK_RETURN, VK_SPACE] then
inherited Click;
inherited;
end;
procedure TGradButton.DoExit;
begin
FState:=bsUp;
FFocused:=false;
InvPaint;
inherited;
end;
procedure TGradButton.Paint;
var
TextOffset : Integer;
tempState: TButtonState;
begin
if not HasParent then
Exit;
with bm do
begin
Width := Self.Width;
Height := Self.Height;
FBackground.Width:=Width;
FBackground.Height:=Height;
Canvas.Brush.Color:=clBlack;
Canvas.FillRect(0,0,Width, Height);
if not FEnabled then
tempState := bsDisabled
else
tempState := FState;
case tempState of
bsUp : Canvas.Draw(0,0,FNormalBackgroundCache);
bsDown: Canvas.Draw(0,0,FDownBackgroundCache);
bsHot : Canvas.Draw(0,0,FHotBackgroundCache);
else Canvas.Draw(0,0,FDisabledBackgroundCache);
end;
TextOffset := IfThen(tempState = bsDown, 1);
DrawRotatedText(Canvas, FTextPoint.x + TextOffset, FTextPoint.y + TextOffset,
FTextSize.cx, FTextSize.cy, Caption, FRotateDirection);
if FShowGlyph and FRotatedGlyph.IsBitmapStored then
begin
FRotatedGlyph.State := FState;
FRotatedGlyph.Draw(bm.Canvas, FGlyphPoint.x+TextOffset, FGlyphPoint.y+TextOffset);
end;
if not (csDesigning in ComponentState) then
if FFocused and FShowFocusBorder then
Canvas.DrawFocusRect(RECT(FBackgroundRect.Left+2, FBackgroundRect.Top+2,
FBackgroundRect.Right-2, FBackgroundRect.Bottom-2));
end;
Canvas.Draw(0,0,bm);
inherited Paint;
end;
procedure TGradButton.MouseEnter;
begin
inherited;
if FState<>bsDown then
begin
FState:=bsHot;
InvPaint(true);
end;
end;
procedure TGradButton.MouseMove(Shift: TShiftState;
X, Y: Integer);
begin
if ssLeft in Shift then
FState := bsDown
else
FState := bsHot;
InvPaint(true);
//inherited MouseMove calls OnMouseMove
inherited MouseMove(Shift, X, Y);
end;
procedure TGradButton.MouseLeave;
begin
inherited;
//WriteLn('MouseLeave');
FState:=bsUp;
//FFocused:=false;
InvPaint(true);
end;
procedure TGradButton.Click;
begin
//inherited;
end;
procedure TGradButton.MouseDown(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if PtInRect(Rect(0,0,Width,Height),Point(X,Y)) then
begin
FState:=bsDown;
InvPaint;
end else begin
FState:=bsUp;
FFocused:=false;
if Assigned(PopupMenu) then
PopupMenu.Close;
InvPaint;
end;
inherited;
end;
procedure TGradButton.MouseUp(Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if PtInRect(Rect(0,0,Width,Height),Point(X,Y)) then
begin
FState:=bsHot;
InvPaint(true);
if Button = mbLeft then
inherited Click; //Faster, than the Overrided Click procedure
end else begin
FState := bsUp;
FFocused:=false;
InvPaint(true);
end;
inherited;
end;
//Thx to: http://www.delphipraxis.net/topic67805_farbverlauf+berechnen.html
function ColorBetween(C1, C2 : TColor; blend:Extended):TColor;
var
r, g, b : Byte;
y1, y2 : Byte;
begin
C1 := ColorToRGB(C1);
C2 := ColorToRGB(C2);
y1 := Red(C1);
y2 := Red(C2);
r := Round(y1 + (y2-y1)*blend);
y1 := Green(C1);
y2 := Green(C2);
g := Round(y1 + (y2-y1)*blend);
y1 := Blue(C1);
y2 := Blue(C2);
b := Round(y1 + (y2-y1)*blend);
Result := RGBToColor(r, g, b);
end;
// Farbe zwischen beliebig vielen vorgegebenen Farbwerten berechnen
function ColorsBetween(colors:array of TColor; blend:Extended):TColor;
var
a : Integer;
faktor : Extended;
begin
if Length(colors) < 2 then
raise Exception.Create('ColorsBetween() at least 2 Colors required');
if blend <= 0.0 then
Result := colors[0]
else if blend >= 1.0 then
Result := colors[High(colors)]
else
begin
a := Trunc(High(colors) * blend);
faktor := 1.0 / High(colors);
Result := ColorBetween(colors[a], colors[a+1], (blend-(a * faktor)) / faktor);
end;
end;
procedure Register;
begin
RegisterComponents('Misc',[TGradButton]);
end;
initialization
{$I tgradbutton.lrs}
end.