Files
ewsdr/FlatButton.pas
T

231 lines
7.5 KiB
ObjectPascal

{
Copyright (C)
2026 - Uladzimir Karpenka, EW8BAK
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
}
unit FlatButton;
{ Кнопка с полным контролем цвета на Windows и Linux.
Используй вместо TButton везде где нужна тёмная тема. }
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Controls, Graphics, LCLType, LMessages, Types;
type
TFlatButton = class(TGraphicControl)
private
FActive: Boolean;
FHot: Boolean;
FClrNorm: TColor;
FClrActive: TColor;
FClrHot: TColor;
FClrBorder: TColor;
FClrText: TColor;
FClrTextAct:TColor;
FOnClick: TNotifyEvent;
procedure SetActive(V: Boolean);
protected
procedure Paint; override;
procedure MouseEnter; override;
procedure MouseLeave; override;
procedure CMTextChanged(var Msg: TLMessage); message CM_TEXTCHANGED;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer); override;
public
constructor Create(AOwner: TComponent); override;
property Active: Boolean read FActive write SetActive;
property ClrNorm: TColor read FClrNorm write FClrNorm;
property ClrActive: TColor read FClrActive write FClrActive;
property ClrHot: TColor read FClrHot write FClrHot;
property ClrBorder: TColor read FClrBorder write FClrBorder;
property ClrText: TColor read FClrText write FClrText;
property ClrTextAct:TColor read FClrTextAct write FClrTextAct;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
property OnMouseDown;
property OnMouseUp;
property Caption;
property Font;
property Enabled;
property Visible;
end;
// Отрисовка кнопки в стиле TFlatButton на произвольном канвасе/прямоугольнике.
// Используется и TFlatButton.Paint, и оверлеями, которые рендерятся в битмап
// (VfoOverlay) — чтобы вид кнопок был одинаковым по всей программе. Шрифт
// берётся текущий у канваса (вызывающий выставляет Name/Size заранее).
procedure PaintFlatButton(C: TCanvas; const R: TRect; const ACaption: string;
AActive, AHot: Boolean;
ClrNorm, ClrActive, ClrHot, ClrBorder, ClrText, ClrTextAct: TColor);
// Фабрика — аналог MakeBtn, возвращает TFlatButton
function MakeFlatBtn(AParent: TWinControl; const ACap: string;
ALeft, ATop, AW, AH: Integer;
AHandler: TNotifyEvent;
ClrNorm: TColor = TColor($00202020);
ClrActive: TColor = TColor($00003300);
ClrHot: TColor = TColor($00303030);
ClrBorder: TColor = TColor($00404040);
ClrText: TColor = TColor($00E0E0E0);
ClrTextAct: TColor = TColor($0000FF88)): TFlatButton;
implementation
constructor TFlatButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FActive := False;
FHot := False;
FClrNorm := TColor($00202020);
FClrActive := TColor($00003300);
FClrHot := TColor($00303030);
FClrBorder := TColor($00404040);
FClrText := TColor($00E0E0E0);
FClrTextAct := TColor($0000FF88);
Cursor := crHandPoint;
end;
procedure TFlatButton.SetActive(V: Boolean);
begin
if FActive = V then Exit;
FActive := V;
Invalidate;
end;
procedure PaintFlatButton(C: TCanvas; const R: TRect; const ACaption: string;
AActive, AHot: Boolean;
ClrNorm, ClrActive, ClrHot, ClrBorder, ClrText, ClrTextAct: TColor);
const
CORNER = 3;
var
BG: TColor;
TW, TH: Integer;
begin
if AActive then BG := ClrActive
else if AHot then BG := ClrHot
else BG := ClrNorm;
// Фон со скруглёнными углами
C.Brush.Color := BG;
C.Brush.Style := bsSolid;
C.Pen.Color := BG;
C.Pen.Style := psSolid;
C.RoundRect(R.Left, R.Top, R.Right, R.Bottom, CORNER * 2, CORNER * 2);
// Рамка
C.Pen.Color := ClrBorder;
C.Brush.Style := bsClear;
C.RoundRect(R.Left, R.Top, R.Right - 1, R.Bottom - 1, CORNER * 2, CORNER * 2);
// Текст
if AActive then C.Font.Color := ClrTextAct
else C.Font.Color := ClrText;
C.Brush.Style := bsClear;
TW := C.TextWidth(ACaption);
TH := C.TextHeight('A');
C.TextOut(R.Left + (R.Right - R.Left - TW) div 2,
R.Top + (R.Bottom - R.Top - TH) div 2, ACaption);
end;
function BlendCol(A, B: TColor; T: Double): TColor;
// Линейная смесь A→B на долю T (0..1); системные цвета резолвим через ColorToRGB.
var ca, cb: LongInt; r, g, bl: Integer;
begin
ca := ColorToRGB(A); cb := ColorToRGB(B);
r := Round((ca and $FF) + ((cb and $FF) - (ca and $FF)) * T);
g := Round(((ca shr 8) and $FF) + (((cb shr 8) and $FF) - ((ca shr 8) and $FF)) * T);
bl := Round(((ca shr 16) and $FF)+ (((cb shr 16) and $FF)- ((ca shr 16) and $FF))* T);
Result := TColor(r or (g shl 8) or (bl shl 16));
end;
procedure TFlatButton.Paint;
begin
if Enabled then
PaintFlatButton(Canvas, ClientRect, Caption, FActive, FHot,
FClrNorm, FClrActive, FClrHot, FClrBorder, FClrText, FClrTextAct)
else
// disabled: не active/не hot, текст и рамка приглушены к фону.
PaintFlatButton(Canvas, ClientRect, Caption, False, False,
FClrNorm, FClrActive, FClrHot,
BlendCol(FClrBorder, FClrNorm, 0.6),
BlendCol(FClrText, FClrNorm, 0.55), FClrTextAct);
end;
procedure TFlatButton.MouseEnter;
begin
inherited;
FHot := True;
Invalidate;
end;
procedure TFlatButton.MouseLeave;
begin
inherited;
FHot := False;
Invalidate;
end;
procedure TFlatButton.CMTextChanged(var Msg: TLMessage);
begin
Invalidate;
end;
procedure TFlatButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
end;
procedure TFlatButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
inherited;
if (Button = mbLeft) and PtInRect(ClientRect, Point(X, Y)) then
if Assigned(FOnClick) then FOnClick(Self);
end;
function MakeFlatBtn(AParent: TWinControl; const ACap: string;
ALeft, ATop, AW, AH: Integer;
AHandler: TNotifyEvent;
ClrNorm, ClrActive, ClrHot, ClrBorder, ClrText, ClrTextAct: TColor): TFlatButton;
begin
Result := TFlatButton.Create(AParent);
Result.Parent := AParent;
Result.Caption := ACap;
Result.Left := ALeft;
Result.Top := ATop;
Result.Width := AW;
Result.Height := AH;
Result.OnClick := AHandler;
Result.ClrNorm := ClrNorm;
Result.ClrActive := ClrActive;
Result.ClrHot := ClrHot;
Result.ClrBorder := ClrBorder;
Result.ClrText := ClrText;
Result.ClrTextAct := ClrTextAct;
Result.Font.Size := 8;
Result.Font.Color := ClrText;
end;
end.