| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458 |
- unit NewStaticText;
- {
- TNewStaticText - similar to TStaticText but with multi-line AutoSize
- support and a WordWrap property, and without a Transparent property.
- Define VCLSTYLES for full VCL Styles support, and for transparency support.
- }
- interface
- uses
- Windows, Messages, SysUtils, Classes, Controls, Forms,
- {$IFDEF VCLSTYLES} Vcl.Themes, {$ELSE} Themes, {$ENDIF}
- Graphics;
- {$IFDEF VCLSTYLES}
- {$DEFINE TRANSPARENCYSUPPORT}
- {$ENDIF}
- type
- TNewStaticText = class(TWinControl)
- private
- FAlignment: TAlignment;
- FAutoSize: Boolean;
- FFocusControl: TWinControl;
- FForceLTRReading: Boolean;
- FLastAdjustBoundsRTL: Boolean;
- FShowAccelChar: Boolean;
- {$IFNDEF TRANSPARENCYSUPPORT}
- FTransparent: Boolean;
- {$ENDIF}
- FWordWrap: Boolean;
- class constructor Create;
- class destructor Destroy;
- {$IFDEF TRANSPARENCYSUPPORT}
- procedure CNCtlColorStatic(var Message: TWMCtlColorStatic); message CN_CTLCOLORSTATIC;
- {$ENDIF}
- 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 SetAlignment(Value: TAlignment);
- procedure SetFocusControl(Value: TWinControl);
- procedure SetForceLTRReading(Value: Boolean);
- procedure SetShowAccelChar(Value: Boolean);
- procedure SetTransparent(const Value: Boolean);
- procedure SetWordWrap(Value: Boolean);
- function GetTransparent: Boolean;
- protected
- procedure CreateParams(var Params: TCreateParams); override;
- procedure Loaded; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetAutoSize(Value: Boolean); override;
- public
- constructor Create(AOwner: TComponent); override;
- function AdjustHeight: Integer;
- function GetControlsAlignment: TAlignment; override;
- published
- property Align;
- property Alignment: TAlignment read FAlignment write SetAlignment
- default taLeftJustify;
- 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 Transparent: Boolean read GetTransparent write SetTransparent
- default True;
- 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;
- TNewStaticTextStyleHook = class(TStyleHook)
- {$IFDEF VCLSTYLES}
- strict protected
- procedure Paint(Canvas: TCanvas); override;
- public
- constructor Create(AControl: TWinControl); override;
- {$ENDIF}
- end;
- procedure Register;
- implementation
- uses
- StdCtrls, Types, BidiUtils;
- procedure Register;
- begin
- RegisterComponents('JR', [TNewStaticText]);
- end;
- { TNewStaticText }
- constructor TNewStaticText.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ControlStyle := [csCaptureMouse, csClickEvents, csSetCaption,
- csReplicatable, csDoubleClicks, csGestures {$IF CompilerVersion >= 35.0}, csNeedsDesignDisabledState{$ENDIF}];
- {$IFNDEF TRANSPARENCYSUPPORT}
- ControlStyle := ControlStyle + [csOpaque];
- FTransparent := True; { Even though Transparent is ignored, we still want it to work as if it isn't at design time }
- {$ENDIF}
- Width := 65;
- Height := 17;
- FAutoSize := True;
- FShowAccelChar := True;
- AdjustBounds;
- end;
- class constructor TNewStaticText.Create;
- begin
- TCustomStyleEngine.RegisterStyleHook(TNewStaticText, TNewStaticTextStyleHook);
- end;
- procedure TNewStaticText.CreateParams(var Params: TCreateParams);
- const
- Alignments: array[Boolean, TAlignment] of DWORD =
- ((SS_LEFT, SS_RIGHT, SS_CENTER), (SS_RIGHT, SS_LEFT, SS_CENTER));
- begin
- inherited CreateParams(Params);
- CreateSubClass(Params, 'STATIC');
- with Params do
- begin
- const AlignmentStyle = Alignments[UseRightToLeftAlignment, FAlignment];
- Style := Style or SS_NOTIFY or AlignmentStyle;
- { Quirk: There are no SS_RIGHTNOWORDWRAP and SS_CENTERNOWORDWRAP styles.
- WordWrap=False still affects AdjustBounds, though. }
- if (AlignmentStyle = SS_LEFT) and not FWordWrap then Style := Style or SS_LEFTNOWORDWRAP;
- if not FShowAccelChar then Style := Style or SS_NOPREFIX;
- if FForceLTRReading then ExStyle := ExStyle and not WS_EX_RTLREADING;
- WindowClass.style := WindowClass.style and not CS_VREDRAW;
- end;
- end;
- class destructor TNewStaticText.Destroy;
- begin
- TCustomStyleEngine.UnregisterStyleHook(TNewStaticText, TNewStaticTextStyleHook);
- 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;
- AdjustBounds;
- end;
- procedure TNewStaticText.CMParentFontChanged(var Message: TMessage);
- begin
- inherited;
- { What we're really trapping here is changes to Parent. Recalculate size
- if the new Parent's RTL setting is different. }
- if IsRightToLeft <> 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.GetControlsAlignment: TAlignment;
- begin
- { This is needed to suppress the WS_EX_RIGHT style when BiDiMode is
- bdRightToLeft and Alignment is not taLeftJustify }
- Result := FAlignment;
- end;
- function TNewStaticText.GetDrawTextFlags: UINT;
- const
- Alignments: array[Boolean, TAlignment] of Word =
- ((DT_LEFT, DT_RIGHT, DT_CENTER), (DT_RIGHT, DT_LEFT, DT_CENTER));
- begin
- const AlignmentFlag = Alignments[UseRightToLeftAlignment, FAlignment];
- Result := DT_EXPANDTABS or DT_NOCLIP or AlignmentFlag;
- if FWordWrap then Result := Result or DT_WORDBREAK;
- if not FShowAccelChar then Result := Result or DT_NOPREFIX;
- if UseRightToLeftReading 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.) }
- 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 := IsRightToLeft;
- 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.SetAlignment(Value: TAlignment);
- begin
- if FAlignment <> Value then
- begin
- FAlignment := Value;
- RecreateWnd;
- end;
- 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;
- {$IFDEF TRANSPARENCYSUPPORT}
- procedure TNewStaticText.CNCtlColorStatic(var Message: TWMCtlColorStatic);
- begin
- { Vcl.StdCtrls' TCustomStaticText.CNCtlColorStatic uses StyleServices(Self).Enabled
- instead of IsCustomStyleActive, but that can return True even when no style is active,
- which is undesirable because when no style is active the inherited call is required to
- support the Font and Brush colors }
- if IsCustomStyleActive and Transparent then
- begin
- SetBkMode(Message.ChildDC, Windows.TRANSPARENT);
- StyleServices(Self).DrawParentBackground(Handle, Message.ChildDC, nil, False);
- { Return an empty brush to prevent Windows from overpainting what we just have created. }
- Message.Result := LRESULT(GetStockObject(NULL_BRUSH));
- end
- else
- inherited;
- end;
- {$ENDIF}
- procedure TNewStaticText.SetTransparent(const Value: Boolean);
- begin
- {$IFDEF TRANSPARENCYSUPPORT}
- if Transparent <> Value then
- begin
- if Value then
- ControlStyle := ControlStyle - [csOpaque]
- else
- ControlStyle := ControlStyle + [csOpaque];
- Invalidate;
- end;
- {$ELSE}
- FTransparent := Value;
- {$ENDIF}
- end;
- function TNewStaticText.GetTransparent: Boolean;
- begin
- {$IFDEF TRANSPARENCYSUPPORT}
- Result := not (csOpaque in ControlStyle);
- {$ELSE}
- Result := FTransparent;
- {$ENDIF}
- end;
- procedure TNewStaticText.SetWordWrap(Value: Boolean);
- begin
- if FWordWrap <> Value then
- begin
- FWordWrap := Value;
- RecreateWnd;
- AdjustBounds;
- end;
- end;
- {$IFDEF VCLSTYLES}
- { TNewStaticTextStyleHook - same as Vcl.StdCtrls' TStaticTextStyleHook
- except that it accesses the Control property as a TNewStaticText instead
- of a TCustomStaticText or TStaticText, and that it uses the control's
- Color property }
- type
- TControlAccess = class(TControl);
- constructor TNewStaticTextStyleHook.Create(AControl: TWinControl);
- begin
- inherited;
- OverridePaint := True;
- OverrideEraseBkgnd := True;
- PaintOnEraseBkgnd := True;
- DoubleBuffered := True;
- end;
- procedure TNewStaticTextStyleHook.Paint(Canvas: TCanvas);
- const
- States: array[Boolean] of TThemedTextLabel = (ttlTextLabelDisabled, ttlTextLabelNormal);
- var
- Details: TThemedElementDetails;
- R: TRect;
- S: String;
- LStyle: TCustomStyleServices;
- begin
- LStyle := StyleServices;
- if LStyle.Available then begin
- R := Control.ClientRect;
- {$IFDEF TRANSPARENCYSUPPORT}
- if TNewStaticText(Control).Transparent then begin
- Details := LStyle.GetElementDetails(tbCheckBoxUncheckedNormal);
- LStyle.DrawParentBackground(Handle, Canvas.Handle, Details, False);
- Canvas.Brush.Style := bsClear;
- end else {$ENDIF} begin
- Canvas.Brush.Color := TNewStaticText(Control).Color;
- Canvas.FillRect(R);
- end;
- Details := LStyle.GetElementDetails(States[Control.Enabled]);
- S := TNewStaticText(Control).Caption;
- if (S = '') or (TNewStaticText(Control).FShowAccelChar and (S[1] = '&') and (S[2] = #0)) then
- S := S + ' ';
- if seFont in Control.StyleElements then
- DrawControlText(Canvas, Details, S, R, TNewStaticText(Control).GetDrawTextFlags)
- else begin
- Canvas.Font := TNewStaticText(Control).Font;
- DrawText(Canvas.Handle, S, Length(S), R, TNewStaticText(Control).GetDrawTextFlags);
- end;
- end;
- end;
- {$ENDIF}
- end.
|