123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338 |
- unit NewStaticText;
- {
- TNewStaticText - similar to TStaticText but with multi-line AutoSize
- support and a WordWrap property
- }
- interface
- uses
- Windows, Messages, SysUtils, Classes, Controls, Forms;
- type
- TNewStaticText = class(TWinControl)
- private
- FAutoSize: Boolean;
- FFocusControl: TWinControl;
- FForceLTRReading: Boolean;
- FLastAdjustBoundsRTL: Boolean;
- FShowAccelChar: Boolean;
- FWordWrap: Boolean;
- procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
- procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
- procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
- procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
- procedure AdjustBounds;
- function CalcBounds: TPoint;
- function GetDrawTextFlags: UINT;
- procedure SetFocusControl(Value: TWinControl);
- procedure SetForceLTRReading(Value: Boolean);
- procedure SetShowAccelChar(Value: Boolean);
- procedure SetWordWrap(Value: Boolean);
- protected
- procedure CreateParams(var Params: TCreateParams); override;
- procedure Loaded; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetAutoSize(Value: Boolean); override;
- procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
- procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
- public
- constructor Create(AOwner: TComponent); override;
- function AdjustHeight: Integer;
- published
- property Align;
- property Anchors;
- property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
- property Caption;
- property Color;
- property DragCursor;
- property DragMode;
- property Enabled;
- property FocusControl: TWinControl read FFocusControl write SetFocusControl;
- property Font;
- property ForceLTRReading: Boolean read FForceLTRReading write SetForceLTRReading
- default False;
- property ParentColor;
- property ParentFont;
- property ParentShowHint;
- property PopupMenu;
- property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar
- default True;
- property ShowHint;
- property StyleElements;
- property StyleName;
- property TabOrder;
- property TabStop;
- property Visible;
- property WordWrap: Boolean read FWordWrap write SetWordWrap default False;
- property OnClick;
- property OnDblClick;
- property OnDragDrop;
- property OnDragOver;
- property OnEndDrag;
- property OnMouseDown;
- property OnMouseMove;
- property OnMouseUp;
- property OnStartDrag;
- end;
- procedure Register;
- implementation
- uses
- Graphics, Themes, Types,
- BidiUtils;
- procedure Register;
- begin
- RegisterComponents('JR', [TNewStaticText]);
- end;
- { TNewStaticText }
- procedure TNewStaticText.WMEraseBkgnd(var Message: TWMEraseBkgnd);
- begin;
- if IsCustomStyleActive and (seClient in StyleElements) then
- Message.Result := 1
- else
- inherited;
- end;
- procedure TNewStaticText.WMPaint(var Message: TWMPaint);
- const
- CStates: array[Boolean] of TThemedTextLabel = (ttlTextLabelDisabled, ttlTextLabelNormal);
- begin
- { Based on Vcl.StdCtrl's TCustomLabel.DoDrawThemeTextEx and its callers. Only the
- DrawParentBackground call is new compared to it. }
- if IsCustomStyleActive and (seClient in StyleElements) then begin
- const LStyle = StyleServices(Self);
- var DC := Message.DC;
- var PS: TPaintStruct;
- if DC = 0 then
- DC := BeginPaint(Handle, PS);
- try
- var R := ClientRect;
- const Details = LStyle.GetElementDetails(CStates[Enabled]);
- LStyle.DrawParentBackground(Handle, DC, Details, False, @R);
- var Text: String := Caption;
- if (Text = '') or (FShowAccelChar and (Text[1] = '&') and (Length(Text) = 1)) then
- Text := Text + ' ';
- const TextFlags = GetDrawTextFlags;
- const OldFont = SelectObject(DC, Font.Handle);
- try
- LStyle.DrawText(DC, Details, Text, R, TTextFormat(TextFlags), Font.Color);
- finally
- SelectObject(DC, OldFont);
- end;
- finally
- if Message.DC = 0 then
- EndPaint(Handle, PS);
- end;
- end else
- inherited;
- end;
- constructor TNewStaticText.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ControlStyle := [csCaptureMouse, csClickEvents, csSetCaption,
- csReplicatable, csDoubleClicks];
- if not (StyleServices.Enabled and not StyleServices.IsSystemStyle) then
- ControlStyle := ControlStyle + [csOpaque];
- Width := 65;
- Height := 17;
- FAutoSize := True;
- FShowAccelChar := True;
- AdjustBounds;
- end;
- procedure TNewStaticText.CreateParams(var Params: TCreateParams);
- begin
- inherited CreateParams(Params);
- CreateSubClass(Params, 'STATIC');
- with Params do
- begin
- Style := Style or SS_NOTIFY;
- if not SetBiDiStyles(Self, Params) then begin
- { Quirk: No style is set for WordWrap=False in RTL mode; WS_EX_RIGHT
- overrides SS_LEFTNOWORDWRAP, and there is no SS_RIGHTNOWORDWRAP style.
- WordWrap=False still affects AdjustBounds, though. }
- if not FWordWrap then Style := Style or SS_LEFTNOWORDWRAP;
- end;
- if not FShowAccelChar then Style := Style or SS_NOPREFIX;
- if FForceLTRReading then ExStyle := ExStyle and not WS_EX_RTLREADING;
- end;
- end;
- procedure TNewStaticText.CMDialogChar(var Message: TCMDialogChar);
- begin
- if (FFocusControl <> nil) and Enabled and ShowAccelChar and
- IsAccel(Message.CharCode, Caption) then
- with FFocusControl do
- if CanFocus then
- begin
- SetFocus;
- Message.Result := 1;
- end;
- end;
- procedure TNewStaticText.CMFontChanged(var Message: TMessage);
- begin
- inherited;
- Invalidate;
- AdjustBounds;
- end;
- procedure TNewStaticText.CMParentFontChanged(var Message: TMessage);
- begin
- inherited;
- Invalidate;
- { What we're really trapping here is changes to Parent. Recalculate size
- if the new Parent's RTL setting is different. }
- if IsParentRightToLeft(Self) <> FLastAdjustBoundsRTL then
- AdjustBounds;
- end;
- procedure TNewStaticText.CMTextChanged(var Message: TMessage);
- begin
- inherited;
- Invalidate;
- AdjustBounds;
- end;
- procedure TNewStaticText.Loaded;
- begin
- inherited Loaded;
- AdjustBounds;
- end;
- function TNewStaticText.GetDrawTextFlags: UINT;
- begin
- Result := DT_EXPANDTABS or DT_NOCLIP;
- if FWordWrap then Result := Result or DT_WORDBREAK;
- if not FShowAccelChar then Result := Result or DT_NOPREFIX;
- if IsParentRightToLeft(Self) then begin
- { Note: DT_RTLREADING must be included even when just calculating the
- size, since on certain fonts it can affect the width of characters.
- (Consider the Hebrew string: 'a '#$F9' b'. On 2000 with Lucida Console
- as the font, the spaces aren't drawn as wide with RTLREADING.) }
- Result := Result or DT_RIGHT;
- if not FForceLTRReading then
- Result := Result or DT_RTLREADING;
- end;
- end;
- function TNewStaticText.CalcBounds: TPoint;
- var
- R: TRect;
- S: String;
- DC: HDC;
- begin
- { Note: The calculated width/height is actually one pixel wider/taller
- than the size of the text, so that when Enabled=False the white shadow
- does not get clipped }
- R := Rect(0, 0, Width, 0);
- if R.Right > 0 then Dec(R.Right);
- S := Caption;
- if (S = '') or (FShowAccelChar and (S[1] = '&') and (Length(S) = 1)) then
- S := S + ' ';
- DC := GetDC(0);
- try
- SelectObject(DC, Font.Handle);
- DrawText(DC, PChar(S), Length(S), R, DT_CALCRECT or GetDrawTextFlags);
- finally
- ReleaseDC(0, DC);
- end;
- Result.X := R.Right + 1;
- Result.Y := R.Bottom + 1;
- end;
- procedure TNewStaticText.AdjustBounds;
- var
- NewBounds: TPoint;
- NewLeft, NewWidth: Integer;
- begin
- if not (csLoading in ComponentState) and FAutoSize then
- begin
- FLastAdjustBoundsRTL := IsParentRightToLeft(Self);
- NewBounds := CalcBounds;
- NewLeft := Left;
- NewWidth := Width;
- if not FWordWrap then begin
- NewWidth := NewBounds.X;
- if IsParentFlipped(Self) then
- Inc(NewLeft, Width - NewWidth);
- end;
- SetBounds(NewLeft, Top, NewWidth, NewBounds.Y);
- end;
- end;
- function TNewStaticText.AdjustHeight: Integer;
- var
- OldHeight: Integer;
- begin
- OldHeight := Height;
- Height := CalcBounds.Y;
- Result := Height - OldHeight;
- end;
- procedure TNewStaticText.Notification(AComponent: TComponent;
- Operation: TOperation);
- begin
- inherited Notification(AComponent, Operation);
- if (Operation = opRemove) and (AComponent = FFocusControl) then
- FFocusControl := nil;
- end;
- procedure TNewStaticText.SetAutoSize(Value: Boolean);
- begin
- if FAutoSize <> Value then
- begin
- FAutoSize := Value;
- if Value then AdjustBounds;
- end;
- end;
- procedure TNewStaticText.SetFocusControl(Value: TWinControl);
- begin
- FFocusControl := Value;
- if Value <> nil then Value.FreeNotification(Self);
- end;
- procedure TNewStaticText.SetForceLTRReading(Value: Boolean);
- begin
- if FForceLTRReading <> Value then begin
- FForceLTRReading := Value;
- RecreateWnd;
- AdjustBounds;
- end;
- end;
- procedure TNewStaticText.SetShowAccelChar(Value: Boolean);
- begin
- if FShowAccelChar <> Value then
- begin
- FShowAccelChar := Value;
- RecreateWnd;
- AdjustBounds;
- end;
- end;
- procedure TNewStaticText.SetWordWrap(Value: Boolean);
- begin
- if FWordWrap <> Value then
- begin
- FWordWrap := Value;
- RecreateWnd;
- AdjustBounds;
- end;
- end;
- end.
|