unit Rux;
interface
uses SysUtils, Types, UITypes, Classes, Graphics, Generics.Defaults,
Generics.Collections;
type
TUxTheme = record
ActiveCaptionColor,
InactiveCaptionColor: TColor;
constructor Create(AActiveCaptionColor, AInactiveCaptionColor: TColor); overload;
constructor Create(ABaseColor: TColor); overload;
function SameWB(AColor: TColor): TColor;
function OtherWB(AColor: TColor): TColor;
function ActiveCaptionTextColor: TColor;
function InactiveCaptionTextColor: TColor;
function DownCaptionColor: TColor;
function DownCaptionTextColor: TColor;
function InactiveTextColor: TColor;
function ColorIsDark(AColor: TColor): Boolean;
function Contrast(AColor1, AColor2: TColor): Boolean;
function Readable(AColor1, AColor2: TColor): Boolean;
end;
TUx = class(TComponent)
private
class var FInstance: TUx;
FThemeData: TUxTheme;
FCallbacks: TDictionary<TComponent, TProc>;
FSimpleCallbacks: TList<TProc>;
procedure CallCallbacks;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation);
override;
public
class constructor ClassCreate;
class destructor ClassDestroy;
class procedure ThemeUpdate(AUxThemeData: TUxTheme); static;
class property ThemeData: TUxTheme read FThemeData;
class procedure RegisterCallback(AComponent: TComponent;
ACallback: TProc); overload; static;
class procedure RegisterCallback(ACallback: TProc); overload; static;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
implementation
uses
ASColors;
constructor TUxTheme.Create(AActiveCaptionColor, AInactiveCaptionColor: TColor);
begin
ActiveCaptionColor := AActiveCaptionColor;
InactiveCaptionColor := AInactiveCaptionColor;
end;
function TUxTheme.ActiveCaptionTextColor: TColor;
begin
Result := OtherWB(ActiveCaptionColor);
end;
function TUxTheme.ColorIsDark(AColor: TColor): Boolean;
begin
Result := ASColors.ColorIsDark(AColor);
end;
function TUxTheme.Contrast(AColor1, AColor2: TColor): Boolean;
begin
Result := Abs(THSL(AColor1).Lightness - THSL(AColor2).Lightness) > 0.5;
end;
function TUxTheme.Readable(AColor1, AColor2: TColor): Boolean;
begin
Result := Abs(THSL(AColor1).Lightness - THSL(AColor2).Lightness) > 0.1;
end;
constructor TUxTheme.Create(ABaseColor: TColor);
var
hsv: THSV;
begin
ActiveCaptionColor := ABaseColor;
hsv := ABaseColor;
hsv.Saturation := hsv.Saturation / 2;
hsv.Value := hsv.Value + (1 - hsv.Value) / 2;
InactiveCaptionColor := hsv;
end;
function TUxTheme.DownCaptionColor: TColor;
begin
Result := SameWB(ActiveCaptionColor);
end;
function TUxTheme.DownCaptionTextColor: TColor;
begin
Result := OtherWB(ActiveCaptionColor);
end;
function TUxTheme.InactiveCaptionTextColor: TColor;
begin
Result := OtherWB(InactiveCaptionColor);
end;
function TUxTheme.InactiveTextColor: TColor;
begin
Result := 0.75*TRGB(InactiveCaptionColor) + 0.25*TRGB(InactiveCaptionTextColor());
end;
function TUxTheme.OtherWB(AColor: TColor): TColor;
begin
if ASColors.ColorIsDark(AColor) then
Result := clWhite
else
Result := clBlack;
end;
function TUxTheme.SameWB(AColor: TColor): TColor;
begin
if ASColors.ColorIsDark(AColor) then
Result := clBlack
else
Result := clWhite;
end;
procedure TUx.CallCallbacks;
begin
if Assigned(FCallbacks) then
for var p in FCallbacks do
if Assigned(p.Value) then
p.Value();
if Assigned(FSimpleCallbacks) then
for var p in FSimpleCallbacks do
if Assigned(p) then
p();
end;
class constructor TUx.ClassCreate;
begin
FInstance := TUx.Create(nil);
end;
class destructor TUx.ClassDestroy;
begin
FreeAndNil(FInstance);
end;
constructor TUx.Create(AOwner: TComponent);
begin
inherited;
FThemeData := TUxTheme.Create($B4855E);
FCallbacks := TDictionary<TComponent, TProc>.Create;
FSimpleCallbacks := TList<TProc>.Create;
end;
destructor TUx.Destroy;
begin
FreeAndNil(FSimpleCallbacks);
FreeAndNil(FCallbacks);
inherited;
end;
procedure TUx.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited;
if Operation = opRemove then
if Assigned(FCallbacks) then
FCallbacks.Remove(AComponent);
end;
class procedure TUx.RegisterCallback(ACallback: TProc);
begin
if Assigned(FInstance) and Assigned(FInstance.FSimpleCallbacks) and Assigned(ACallback) then
begin
FInstance.FSimpleCallbacks.Add(ACallback);
ACallback();
end;
end;
class procedure TUx.RegisterCallback(AComponent: TComponent; ACallback: TProc);
begin
if Assigned(FInstance) and Assigned(FInstance.FCallbacks) and Assigned(AComponent) and Assigned(ACallback) then
begin
AComponent.FreeNotification(FInstance);
FInstance.FCallbacks.Add(AComponent, ACallback);
ACallback();
end;
end;
class procedure TUx.ThemeUpdate(AUxThemeData: TUxTheme);
begin
if Assigned(FInstance) then
begin
FInstance.FThemeData := AUxThemeData;
FInstance.CallCallbacks;
end;
end;
end.