1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/packages/my/PathLabel.pas
Martin Prikryl d3c47a0481 Dark theme for progress window (part of Issue 1696)
https://winscp.net/tracker/1696

Source commit: 47fcfc8dad350a518be9ccfd53ee9d07fb4943b7
2025-05-27 01:09:16 +02:00

1010 lines
26 KiB
ObjectPascal

unit PathLabel;
interface
{$WARN UNIT_PLATFORM OFF}
uses
Messages, StdCtrls, Controls, Classes, Forms, Windows, Graphics;
type
TCustomPathLabel = class;
TPathLabelGetStatusEvent = procedure(Sender: TCustomPathLabel; var Active: Boolean) of object;
TPathLabelPathClickEvent = procedure(Sender: TCustomPathLabel; Path: string) of object;
TCustomPathLabel = class(TCustomLabel)
private
FColors: array[0..5] of TColor;
FIndentHorizontal: Integer;
FIndentVertical: Integer;
FUnixPath: Boolean;
FOnGetStatus: TPathLabelGetStatusEvent;
FOnPathClick: TPathLabelPathClickEvent;
FOnMaskClick: TNotifyEvent;
FDisplayPath: string;
FShortenedDisplayPath: string;
FShortenedPath: string;
FDisplayHotTrack: string;
FDisplayMask: string;
FHotTrack: Boolean;
FMouseInView: Boolean;
FIsActive: Boolean;
FIsEnabled: Boolean;
FMask: string;
FAutoSizeVertical: Boolean;
procedure CMHintShow(var Message: TMessage); message CM_HINTSHOW;
procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
function GetColors(Index: Integer): TColor;
procedure SetColors(Index: Integer; Value: TColor);
procedure SetIndentHorizontal(AIndent: Integer);
procedure SetIndentVertical(AIndent: Integer);
procedure SetUnixPath(AUnixPath: Boolean);
procedure SetMask(Value: string);
procedure SetAutoSizeVertical(Value: Boolean);
procedure SetFocusControl(Value: TWinControl);
function GetFocusControl: TWinControl;
function CalculateAutoHotTrackColor(C: TColor): TColor;
procedure CalculateAutoHotTrackColors;
function CalculateAutoHotTrackColorComponent(C: Byte; Bright: Boolean): Byte;
function UseHotTrack: Boolean;
protected
procedure AdjustBounds; override;
procedure Click; override;
procedure DoDrawTextIntern(var Rect: TRect; Flags: Longint; S: string);
procedure DoDrawText(var Rect: TRect; Flags: Longint); override;
procedure Notification(AComponent: TComponent;
Operation: TOperation); override;
procedure Paint; override;
function IsActive: Boolean;
function TrackingActive: Boolean;
function HotTrackPath: string;
function GetSeparator: Char;
procedure MouseMove(Shift: TShiftState; X: Integer; Y: Integer); override;
procedure DoPathClick(Path: string); virtual;
procedure DoMaskClick;
procedure DblClick; override;
procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
public
constructor Create(AnOwner: TComponent); override;
procedure UpdateStatus;
function UseRightToLeftAlignment: Boolean; override;
property ActiveColor: TColor index 1 read GetColors write SetColors
default clActiveCaption;
property ActiveTextColor: TColor index 3 read GetColors write SetColors
default clCaptionText;
property UnixPath: Boolean read FUnixPath write SetUnixPath default False;
property IndentHorizontal: Integer read FIndentHorizontal
write SetIndentHorizontal default 5;
property IndentVertical: Integer read FIndentVertical
write SetIndentVertical default 1;
property InactiveColor: TColor index 0 read GetColors write SetColors
default clInactiveCaption;
property InactiveTextColor: TColor index 2 read GetColors write SetColors
default clInactiveCaptionText;
property OnGetStatus: TPathLabelGetStatusEvent read FOnGetStatus write FOnGetStatus;
property OnPathClick: TPathLabelPathClickEvent read FOnPathClick write FOnPathClick;
property OnMaskClick: TNotifyEvent read FOnMaskClick write FOnMaskClick;
property HotTrack: Boolean read FHotTrack write FHotTrack default False;
property Mask: string read FMask write SetMask;
property AutoSizeVertical: Boolean read FAutoSizeVertical write SetAutoSizeVertical default False;
property FocusControl: TWinControl read GetFocusControl write SetFocusControl;
property Caption;
property Hint stored False;
property Align default alTop;
end;
type
TPathLabel = class(TCustomPathLabel)
published
property ActiveColor;
property ActiveTextColor;
property UnixPath;
property IndentHorizontal;
property IndentVertical;
property InactiveColor;
property InactiveTextColor;
property AutoSizeVertical;
property HotTrack;
property OnGetStatus;
property OnPathClick;
property OnMaskClick;
property Align;
property Alignment;
property Anchors;
property AutoSize;
property BiDiMode;
property Constraints;
property DragCursor;
property DragKind;
property DragMode;
property Enabled;
property Font;
property ParentBiDiMode;
property ParentFont;
property PopupMenu;
property Transparent;
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDock;
property OnEndDrag;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDock;
property OnStartDrag;
end;
procedure Register;
implementation
uses
{ SysUtils must overload deprecated FileCtrl (implements MinimizeName) }
FileCtrl, SysUtils, Math, PasTools, StrUtils;
const
// magic value
HotTrackMask: string = #1;
procedure Register;
begin
RegisterComponents('Martin', [TPathLabel]);
end;
{ TCustomPathLabel }
constructor TCustomPathLabel.Create(AnOwner: TComponent);
begin
inherited Create(AnOwner);
WordWrap := False;
Align := alTop;
ShowAccelChar := False;
FIndentHorizontal := 5;
FIndentVertical := 1;
FUnixPath := False;
FHotTrack := False;
FColors[0] := clInactiveCaption;
FColors[1] := clActiveCaption;
FColors[2] := clInactiveCaptionText;
FColors[3] := clCaptionText;
FIsEnabled := True;
CalculateAutoHotTrackColors;
end;
procedure TCustomPathLabel.CMHintShow(var Message: TMessage);
begin
with TCMHintShow(Message).HintInfo^ do
begin
HintPos.X := ClientOrigin.X + IndentHorizontal;
HintPos.Y := ClientOrigin.Y + IndentVertical;
if UseHotTrack then Inc(HintPos.Y, Height);
end;
end; { CMHintShow }
procedure TCustomPathLabel.Click;
var
HotPath: string;
begin
if FIsEnabled then
begin
HotPath := HotTrackPath;
if HotPath <> '' then
begin
if HotPath = HotTrackMask then DoMaskClick
else
begin
if FShortenedPath <> '' then
begin
// No matter the shortening algo, when the clicked path is the full displayed path, use full original path
if HotPath = FDisplayPath then HotPath := Caption
else
begin
Assert(FShortenedDisplayPath <> '');
Assert((Length(HotPath) >= Length(FShortenedDisplayPath)) or (not ContainsStr(HotPath, '...')));
if Length(HotPath) >= Length(FShortenedDisplayPath) then
begin
Assert(StartsStr(FShortenedDisplayPath, HotPath));
if StartsStr(FShortenedDisplayPath, HotPath) then
begin
Delete(HotPath, 1, Length(FShortenedDisplayPath));
HotPath := FShortenedPath + HotPath;
end;
end;
end;
end;
if EndsStr(GetSeparator, HotPath) and
(HotPath <> GetSeparator) then
SetLength(HotPath, Length(HotPath) - 1);
DoPathClick(HotPath);
end;
end;
if Assigned(FocusControl) then FocusControl.SetFocus;
inherited;
end;
end; { Click }
procedure TCustomPathLabel.SetUnixPath(AUnixPath: Boolean);
begin
if FUnixPath <> AUnixPath then
begin
FUnixPath := AUnixPath;
AdjustBounds;
Invalidate;
end;
end;
procedure TCustomPathLabel.SetMask(Value: string);
begin
if FMask <> Value then
begin
FMask := Value;
AdjustBounds;
Invalidate;
end;
end;
procedure TCustomPathLabel.SetColors(Index: integer; Value: TColor);
begin
Assert(Index in [0..3]);
if FColors[Index] <> Value then
begin
FColors[Index] := Value;
CalculateAutoHotTrackColors;
UpdateStatus;
end;
end; { SetColors }
// taken from PngImageListEditor
const
WeightR: single = 0.764706;
WeightG: single = 1.52941;
WeightB: single = 0.254902;
function ColorDistance(C1, C2: Integer): Single;
var
DR, DG, DB: Integer;
begin
DR := (C1 and $FF) - (C2 and $FF);
Result := Sqr(DR * WeightR);
DG := (C1 shr 8 and $FF) - (C2 shr 8 and $FF);
Result := Result + Sqr(DG * WeightG);
DB := (C1 shr 16) - (C2 shr 16);
Result := Result + Sqr(DB * WeightB);
Result := Sqrt(Result);
end;
function GetAdjustedThreshold(BkgndIntensity, Threshold: Single): Single;
begin
if BkgndIntensity < 220 then
Result := (2 - BkgndIntensity / 220) * Threshold
else
Result := Threshold;
end;
function IsContrastEnough(AColor, ABkgndColor: Integer; DoAdjustThreshold: Boolean; Threshold: Single): Boolean;
begin
if DoAdjustThreshold then
Threshold := GetAdjustedThreshold(ColorDistance(ABkgndColor, $000000),
Threshold);
Result := ColorDistance(ABkgndColor, AColor) > Threshold;
end;
procedure AdjustContrast(var AColor: Integer; ABkgndColor: Integer; Threshold: Single);
var
X, Y, Z: Single;
R, G, B: Single;
RR, GG, BB: Integer;
I1, I2, S, Q, W: Single;
DoInvert: Boolean;
begin
I1 := ColorDistance(AColor, $000000);
I2 := ColorDistance(ABkgndColor, $000000);
Threshold := GetAdjustedThreshold(I2, Threshold);
if I1 > I2 then
DoInvert := I2 < 442 - Threshold
else
DoInvert := I2 < Threshold;
X := (ABkgndColor and $FF) * WeightR;
Y := (ABkgndColor shr 8 and $FF) * WeightG;
Z := (ABkgndColor shr 16) * WeightB;
R := (AColor and $FF) * WeightR;
G := (AColor shr 8 and $FF) * WeightG;
B := (AColor shr 16) * WeightB;
if DoInvert then begin
R := 195 - R;
G := 390 - G;
B := 65 - B;
X := 195 - X;
Y := 390 - Y;
Z := 65 - Z;
end;
S := Sqrt(Sqr(B) + Sqr(G) + Sqr(R));
if S < 0.01 then
S := 0.01;
Q := (R * X + G * Y + B * Z) / S;
X := Q / S * R - X;
Y := Q / S * G - Y;
Z := Q / S * B - Z;
W := Sqrt(Sqr(Threshold) - Sqr(X) - Sqr(Y) - Sqr(Z));
R := (Q - W) * R / S;
G := (Q - W) * G / S;
B := (Q - W) * B / S;
if DoInvert then begin
R := 195 - R;
G := 390 - G;
B := 65 - B;
end;
if R < 0 then
R := 0
else if R > 195 then
R := 195;
if G < 0 then
G := 0
else if G > 390 then
G := 390;
if B < 0 then
B := 0
else if B > 65 then
B := 65;
RR := Trunc(R * (1 / WeightR) + 0.5);
GG := Trunc(G * (1 / WeightG) + 0.5);
BB := Trunc(B * (1 / WeightB) + 0.5);
if RR > $FF then
RR := $FF
else if RR < 0 then
RR := 0;
if GG > $FF then
GG := $FF
else if GG < 0 then
GG := 0;
if BB > $FF then
BB := $FF
else if BB < 0 then
BB := 0;
AColor := (BB and $FF) shl 16 or (GG and $FF) shl 8 or (RR and $FF);
end;
procedure SetContrast(var Color: TColor; BkgndColor: TColor; Threshold: Integer);
var
T: Single;
begin
if Color < 0 then
Color := GetSysColor(Color and $FF);
if BkgndColor < 0 then
BkgndColor := GetSysColor(BkgndColor and $FF);
T := Threshold;
if not IsContrastEnough(Color, BkgndColor, True, T) then
AdjustContrast(Integer(Color), BkgndColor, T);
end;
function TCustomPathLabel.CalculateAutoHotTrackColorComponent(C: Byte; Bright: Boolean): Byte;
var
Delta: Byte;
begin
Delta := Max(Round(C * 0.3), 80);
if Bright then
Result := Byte(Max(Integer(C) - Delta, 0))
else
Result := Byte(Min(C + Delta, 255));
end;
function TCustomPathLabel.CalculateAutoHotTrackColor(C: TColor): TColor;
var
R, G, B: Byte;
Bright: Boolean;
begin
C := ColorToRGB(C);
R := GetRValue(C);
G := GetGValue(C);
B := GetBValue(C);
Bright := (R + G + B) > (256 / 2 * 3);
R := CalculateAutoHotTrackColorComponent(R, Bright);
G := CalculateAutoHotTrackColorComponent(G, Bright);
B := CalculateAutoHotTrackColorComponent(B, Bright);
Result := RGB(R, G, B);
end;
procedure TCustomPathLabel.CalculateAutoHotTrackColors;
begin
FColors[4] := CalculateAutoHotTrackColor(FColors[2]);
SetContrast(FColors[4], FColors[0], 50);
FColors[5] := CalculateAutoHotTrackColor(FColors[3]);
SetContrast(FColors[5], FColors[1], 50);
end;
procedure TCustomPathLabel.SetIndentHorizontal(AIndent: Integer);
begin
if FIndentHorizontal <> AIndent then
begin
FIndentHorizontal := AIndent;
AdjustBounds;
Invalidate;
end;
end;
procedure TCustomPathLabel.SetIndentVertical(AIndent: Integer);
begin
if FIndentVertical <> AIndent then
begin
FIndentVertical := AIndent;
AdjustBounds;
Invalidate;
end;
end;
procedure TCustomPathLabel.SetAutoSizeVertical(Value: Boolean);
begin
if FAutoSizeVertical <> Value then
begin
FAutoSizeVertical := Value;
AdjustBounds;
Invalidate;
end;
end;
function TCustomPathLabel.GetFocusControl: TWinControl;
begin
Result := inherited FocusControl;
end;
procedure TCustomPathLabel.SetFocusControl(Value: TWinControl);
begin
if FocusControl <> Value then
begin
inherited FocusControl := Value;
UpdateStatus;
end;
end;
function MinimizeStr(Buf: string; Canvas: TCanvas; Width: Integer): string;
var
StrWidth: Integer;
begin
if Canvas.TextWidth(Buf) > Width then
begin
Buf := Buf + '...';
repeat
Delete(Buf, Length(Buf) - 3, 1);
StrWidth := Canvas.TextWidth(Buf);
until (StrWidth <= Width) or (Length(Buf) = 4);
end;
Result := Buf;
end;
function ConvertPath(Path: string; S1, S2: Char): string;
var
I: Integer;
begin
for I := 1 to Length(Path) do
begin
if Path[I] = S1 then Path[I] := S2
else
if Path[I] = S2 then Path[I] := S1;
end;
Result := Path;
end;
function ConvertPathToWin(Path: string): string;
begin
Result := ConvertPath(Path, '/', '\');
end;
function ConvertPathToUnix(Path: string): string;
begin
Result := ConvertPath(Path, '\', '/');
end;
procedure TCustomPathLabel.DoDrawTextIntern(var Rect: TRect; Flags: Longint; S: string);
var
I, I2, L: Integer;
Width: Integer;
WidthMask: Integer;
WidthPath: Integer;
WidthRemain: Integer;
HotTrackOffset: Integer;
HotTrackBottom: Integer;
Separator, Buf, Buf2: string;
Str: string;
HotTrackColor, OrigColor: TColor;
VirtualMask: string;
IsEmptyMask: Boolean;
IsVirtualMask: Boolean;
begin
if (Flags and DT_CALCRECT <> 0) and ((S = '') or ShowAccelChar and
(S[1] = '&') and (S[2] = #0)) then S := S + ' ';
if not ShowAccelChar then Flags := Flags or DT_NOPREFIX;
// have to apply DrawTextBiDiModeFlags if we ever deal with dibi
Canvas.Font := Font;
Width := (Rect.Right - Rect.Left);
FDisplayPath := S;
VirtualMask := Mask;
IsVirtualMask := False;
IsEmptyMask := (VirtualMask = '');
if IsEmptyMask and UseHotTrack then
begin
VirtualMask := '*.*';
IsVirtualMask := not FMouseInView;
end;
Separator := GetSeparator;
if VirtualMask <> '' then
begin
if (Length(FDisplayPath) > 0) and (FDisplayPath[Length(FDisplayPath)] <> GetSeparator) then
Buf := Separator;
FDisplayPath := FDisplayPath + Buf;
S := S + Buf;
WidthMask := Canvas.TextWidth(VirtualMask);
if WidthMask > Width div 3 then
WidthPath := Width - (Width div 3)
else
WidthPath := Width - WidthMask;
end
else
begin
WidthMask := 0;
WidthPath := Width;
end;
if FUnixPath then
FDisplayPath := ConvertPathToWin(FDisplayPath);
Buf := FDisplayPath;
WidthRemain := WidthPath;
if EndsStr('\', FDisplayPath) then
begin
Dec(WidthRemain, Canvas.TextWidth('\'));
SetLength(Buf, Length(Buf) - 1);
end;
Buf2 := ExtractFileName(Buf);
FShortenedDisplayPath := '...\';
if WidthRemain < Canvas.TextWidth(FShortenedDisplayPath + Buf2) then
begin
Dec(WidthRemain, Canvas.TextWidth(FShortenedDisplayPath));
Buf2 := MinimizeStr(Buf2, Canvas, WidthRemain);
FShortenedPath := ExtractFilePath(Buf);
Buf := FShortenedDisplayPath + Buf2;
end
else
begin
Buf2 := MinimizeName(Buf, Canvas, WidthRemain);
if Buf2 = Buf then
begin
FShortenedPath := '';
FShortenedDisplayPath := '';
end
else
begin
I := Length(Buf);
repeat
I2 := LastDelimiter('\', Copy(Buf, 1, I - 1));
if I2 = 0 then
Break;
L := Length(Buf) - I2 + 1;
if Copy(Buf, I2, L) = Copy(Buf2, Length(Buf2) - L + 1, L) then
I := I2
else
Break;
until False;
FShortenedPath := Copy(Buf, 1, I);
FShortenedDisplayPath := Copy(Buf2, 1, Length(Buf2) - (Length(Buf) - I));
Buf := Buf2;
end;
end;
if EndsStr('\', FDisplayPath) then
begin
Buf := Buf + '\';
end;
FDisplayPath := Buf;
if FUnixPath then
begin
FDisplayPath := ConvertPathToUnix(FDisplayPath);
FShortenedPath := ConvertPathToUnix(FShortenedPath);
FShortenedDisplayPath := ConvertPathToUnix(FShortenedDisplayPath);
end;
WidthPath := Canvas.TextWidth(FDisplayPath);
if VirtualMask <> '' then
begin
VirtualMask := MinimizeStr(VirtualMask, Canvas, Width - WidthPath);
WidthMask := Canvas.TextWidth(VirtualMask);
end;
Str := FDisplayPath;
if not IsVirtualMask then
begin
Str := Str + VirtualMask;
FDisplayMask := VirtualMask;
end
else
begin
FDisplayMask := '';
end;
ShowHint :=
(FDisplayPath <> S) or
((not IsEmptyMask) and (FDisplayMask <> Mask)) or
(WidthPath + WidthMask > Width);
if not ShowHint then Hint := ''
else Hint := S + Mask;
if not FIsEnabled then
begin
Canvas.Font.Color := clBtnShadow;
DrawText(Canvas.Handle, PChar(Str), Length(Str), Rect, Flags);
end
else
begin
FDisplayHotTrack := HotTrackPath;
HotTrackColor := TColor(0); // shut up
if FDisplayHotTrack <> '' then
begin
if TrackingActive then
begin
HotTrackColor := FColors[4 + Integer(FIsActive)]
end
else
begin
// We do not have a path label with hot-track and not tracking-active,
// so this is untested branch
Assert(False);
// As if it were active
HotTrackColor := FColors[2 + 1];
end;
end;
OrigColor := Canvas.Font.Color;
if (FDisplayHotTrack <> '') and (FDisplayHotTrack <> HotTrackMask) then
begin
Canvas.Font.Color := HotTrackColor;
DrawText(Canvas.Handle, PChar(FDisplayHotTrack), Length(FDisplayHotTrack), Rect, Flags);
HotTrackOffset := Canvas.TextWidth(FDisplayHotTrack);
Inc(Rect.Left, HotTrackOffset);
Delete(Str, 1, Length(FDisplayHotTrack));
HotTrackBottom := Rect.Bottom;
end
else
begin
HotTrackOffset := 0;
HotTrackBottom := 0;
end;
if TrackingActive then
Canvas.Font.Color := FColors[2 + Integer(FIsActive)]
else
Canvas.Font.Color := OrigColor;
if FDisplayHotTrack = HotTrackMask then
begin
DrawText(Canvas.Handle, PChar(FDisplayPath), Length(FDisplayPath), Rect, Flags);
HotTrackOffset := Canvas.TextWidth(FDisplayPath);
HotTrackBottom := Rect.Bottom;
Inc(Rect.Left, HotTrackOffset);
Canvas.Font.Color := HotTrackColor;
DrawText(Canvas.Handle, PChar(VirtualMask), Length(VirtualMask), Rect, Flags);
end
else
begin
DrawText(Canvas.Handle, PChar(Str), Length(Str), Rect, Flags);
end;
Dec(Rect.Left, HotTrackOffset);
Rect.Bottom := Max(Rect.Bottom, HotTrackBottom);
end;
end;
procedure TCustomPathLabel.DoDrawText(var Rect: TRect; Flags: Longint);
begin
DoDrawTextIntern(Rect, Flags, Caption);
end;
function TCustomPathLabel.GetSeparator: Char;
begin
if FUnixPath then Result := '/'
else Result := '\';
end;
function TCustomPathLabel.HotTrackPath: string;
var
P: TPoint;
DelimPos: Integer;
Len: Integer;
Path: string;
begin
Result := '';
if UseHotTrack and FMouseInView and (FDisplayPath <> '') then
begin
P := ScreenToClient(Mouse.CursorPos);
Len := P.X - FIndentHorizontal;
if Len >= 0 then
begin
if Len < Canvas.TextWidth(FDisplayPath) then
begin
Result := '';
Path := FDisplayPath;
repeat
Assert(Path <> '');
if (not FUnixPath) and (Result = '') and IsUncPath(Path) then
begin
Result := ExtractFileDrive(Path);
if Copy(Path, Length(Result) + 1, 1) = GetSeparator then
begin
Result := Result + GetSeparator;
end;
Delete(Path, 1, Length(Result));
end
else
begin
DelimPos := Pos(GetSeparator, Path);
if DelimPos > 0 then
begin
Result := Result + Copy(Path, 1, DelimPos);
Delete(Path, 1, DelimPos);
end
else
begin
Result := Result + Path;
Path := '';
end;
end;
until (Canvas.TextWidth(Result) >= Len) or (Path = '');
end
else
if Len < Canvas.TextWidth(FDisplayPath + FDisplayMask) then
begin
Result := HotTrackMask;
end;
end;
end;
end;
function TCustomPathLabel.GetColors(Index: Integer): TColor;
begin
Assert(Index in [0..5]);
Result := FColors[Index];
end; { GetColors }
function TCustomPathLabel.UseRightToLeftAlignment: Boolean;
begin
// Not sure how to properly deal with RTL atm.
// See also a comment on DrawTextBiDiModeFlags in DoDrawTextIntern
Result := False;
end;
procedure TCustomPathLabel.Paint;
const
Alignments: array[TAlignment] of Word = (DT_LEFT, DT_RIGHT, DT_CENTER);
WordWraps: array[Boolean] of Word = (0, DT_WORDBREAK);
var
Rect, CalcRect: TRect;
DrawStyle: Longint;
begin
with Canvas do
begin
if not Transparent then
begin
Brush.Color := Self.Color;
Brush.Style := bsSolid;
FillRect(ClientRect);
end;
Brush.Style := bsClear;
Rect := ClientRect;
// DoDrawText takes care of BiDi alignments
DrawStyle := DT_EXPANDTABS or WordWraps[WordWrap] or Alignments[Alignment];
// MP
Rect.Left := Rect.Left + FIndentHorizontal;
Rect.Right := Rect.Right - FIndentHorizontal;
Rect.Top := Rect.Top + FIndentVertical;
Rect.Bottom := Rect.Bottom - FIndentVertical;
// Calculate vertical layout
if Layout <> tlTop then
begin
CalcRect := Rect;
DoDrawText(CalcRect, DrawStyle or DT_CALCRECT);
if Layout = tlBottom then OffsetRect(Rect, 0, Height - CalcRect.Bottom)
else OffsetRect(Rect, 0, (Height - CalcRect.Bottom) div 2);
end;
DoDrawText(Rect, DrawStyle);
end;
end;
procedure TCustomPathLabel.AdjustBounds;
const
WordWraps: array[Boolean] of Word = (0, DT_WORDBREAK);
var
DC: HDC;
X: Integer;
Rect: TRect;
AAlignment: TAlignment;
AWidth: Integer;
AHeight: Integer;
S: string;
begin
if not (csReading in ComponentState) and
(AutoSize or AutoSizeVertical) then
begin
Rect := ClientRect;
DC := GetDC(0);
Canvas.Handle := DC;
S := Caption;
if S = '' then S := 'SomeTextForSizing';
DoDrawTextIntern(Rect, (DT_EXPANDTABS or DT_CALCRECT) or WordWraps[WordWrap], S);
Canvas.Handle := 0;
ReleaseDC(0, DC);
X := Left;
AAlignment := Alignment;
if UseRightToLeftAlignment then ChangeBiDiModeAlignment(AAlignment);
if AAlignment = taRightJustify then Inc(X, Width - 2*FIndentHorizontal + Rect.Right);
if AutoSize then AWidth := 2*FIndentHorizontal + Rect.Right
else AWidth := Width;
if AutoSize or AutoSizeVertical then AHeight := 2*FIndentVertical + Rect.Bottom
else AHeight := Height;
SetBounds(X, Top, AWidth, AHeight);
end;
end;
function TCustomPathLabel.IsActive: Boolean;
begin
if csDestroying in ComponentState then Result := False
else
begin
Result := Assigned(FocusControl) and FocusControl.Focused;
if Assigned(OnGetStatus) then
OnGetStatus(Self, Result);
end;
end;
function TCustomPathLabel.TrackingActive: Boolean;
begin
Result := Assigned(FocusControl) or Assigned(OnGetStatus);
end;
procedure TCustomPathLabel.UpdateStatus;
var
NewIsActive: Boolean;
NewIsEnabled: Boolean;
NewColor: TColor;
begin
if TrackingActive then
begin
NewIsActive := IsActive;
NewIsEnabled :=
Enabled and
((not Assigned(FocusControl)) or FocusControl.Enabled);
NewColor := FColors[Integer(NewIsActive)];
if (NewIsActive <> FIsActive) or
(NewIsEnabled <> FIsEnabled) or
(NewColor <> Color) then
begin
FIsActive := NewIsActive;
FIsEnabled := NewIsEnabled;
Color := NewColor;
Invalidate;
end;
end
else
begin
Color := clBtnFace;
end;
end; { UpdateStatus }
procedure TCustomPathLabel.Notification(AComponent: TComponent;
Operation: TOperation);
var
NeedUpdate: Boolean;
begin
NeedUpdate :=
(Operation = opRemove) and (AComponent = FocusControl);
inherited;
if NeedUpdate then UpdateStatus;
end; { Notification }
function TCustomPathLabel.UseHotTrack: Boolean;
begin
Result := HotTrack and FIsEnabled;
end;
procedure TCustomPathLabel.MouseMove(Shift: TShiftState; X: Integer; Y: Integer);
begin
inherited;
if FMouseInView and UseHotTrack and (FDisplayHotTrack <> HotTrackPath) then
begin
Invalidate;
end;
end;
procedure TCustomPathLabel.DoPathClick(Path: string);
begin
if Assigned(OnPathClick) then
OnPathClick(Self, Path);
end;
procedure TCustomPathLabel.DoMaskClick;
begin
if Assigned(OnMaskClick) then
OnMaskClick(Self);
end;
procedure TCustomPathLabel.DblClick;
begin
if FIsEnabled then
begin
inherited;
end;
end;
procedure TCustomPathLabel.DoContextPopup(MousePos: TPoint; var Handled: Boolean);
begin
if FIsEnabled then
begin
inherited;
end
else
begin
Handled := True;
end;
end;
procedure TCustomPathLabel.CMMouseEnter(var Message: TMessage);
begin
inherited;
FMouseInView := True;
Invalidate;
end;
procedure TCustomPathLabel.CMMouseLeave(var Message: TMessage);
begin
FMouseInView := False;
Invalidate;
inherited;
end;
end.