1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009 |
- 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.
|