NewStaticText.pas 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. unit NewStaticText;
  2. {
  3. TNewStaticText - similar to TStaticText but with multi-line AutoSize
  4. support and a WordWrap property
  5. }
  6. interface
  7. uses
  8. Windows, Messages, SysUtils, Classes, Controls, Forms;
  9. type
  10. TNewStaticText = class(TWinControl)
  11. private
  12. FAutoSize: Boolean;
  13. FFocusControl: TWinControl;
  14. FForceLTRReading: Boolean;
  15. FLastAdjustBoundsRTL: Boolean;
  16. FShowAccelChar: Boolean;
  17. FWordWrap: Boolean;
  18. procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  19. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  20. procedure CMParentFontChanged(var Message: TMessage); message CM_PARENTFONTCHANGED;
  21. procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  22. procedure AdjustBounds;
  23. function CalcBounds: TPoint;
  24. function GetDrawTextFlags: UINT;
  25. procedure SetFocusControl(Value: TWinControl);
  26. procedure SetForceLTRReading(Value: Boolean);
  27. procedure SetShowAccelChar(Value: Boolean);
  28. procedure SetWordWrap(Value: Boolean);
  29. protected
  30. procedure CreateParams(var Params: TCreateParams); override;
  31. procedure Loaded; override;
  32. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  33. procedure SetAutoSize(Value: Boolean); override;
  34. public
  35. constructor Create(AOwner: TComponent); override;
  36. function AdjustHeight: Integer;
  37. published
  38. property Align;
  39. property Anchors;
  40. property AutoSize: Boolean read FAutoSize write SetAutoSize default True;
  41. property Caption;
  42. property Color;
  43. property DragCursor;
  44. property DragMode;
  45. property Enabled;
  46. property FocusControl: TWinControl read FFocusControl write SetFocusControl;
  47. property Font;
  48. property ForceLTRReading: Boolean read FForceLTRReading write SetForceLTRReading
  49. default False;
  50. property ParentColor;
  51. property ParentFont;
  52. property ParentShowHint;
  53. property PopupMenu;
  54. property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar
  55. default True;
  56. property ShowHint;
  57. property TabOrder;
  58. property TabStop;
  59. property Visible;
  60. property WordWrap: Boolean read FWordWrap write SetWordWrap default False;
  61. property OnClick;
  62. property OnDblClick;
  63. property OnDragDrop;
  64. property OnDragOver;
  65. property OnEndDrag;
  66. property OnMouseDown;
  67. property OnMouseMove;
  68. property OnMouseUp;
  69. property OnStartDrag;
  70. end;
  71. procedure Register;
  72. implementation
  73. uses
  74. BidiUtils;
  75. procedure Register;
  76. begin
  77. RegisterComponents('JR', [TNewStaticText]);
  78. end;
  79. { TNewStaticText }
  80. constructor TNewStaticText.Create(AOwner: TComponent);
  81. begin
  82. inherited Create(AOwner);
  83. ControlStyle := [csCaptureMouse, csClickEvents, csSetCaption,
  84. csOpaque, csReplicatable, csDoubleClicks];
  85. Width := 65;
  86. Height := 17;
  87. FAutoSize := True;
  88. FShowAccelChar := True;
  89. AdjustBounds;
  90. end;
  91. procedure TNewStaticText.CreateParams(var Params: TCreateParams);
  92. begin
  93. inherited CreateParams(Params);
  94. CreateSubClass(Params, 'STATIC');
  95. with Params do
  96. begin
  97. Style := Style or SS_NOTIFY;
  98. if not SetBiDiStyles(Self, Params) then begin
  99. { Quirk: No style is set for WordWrap=False in RTL mode; WS_EX_RIGHT
  100. overrides SS_LEFTNOWORDWRAP, and there is no SS_RIGHTNOWORDWRAP style.
  101. WordWrap=False still affects AdjustBounds, though. }
  102. if not FWordWrap then Style := Style or SS_LEFTNOWORDWRAP;
  103. end;
  104. if not FShowAccelChar then Style := Style or SS_NOPREFIX;
  105. if FForceLTRReading then ExStyle := ExStyle and not WS_EX_RTLREADING;
  106. end;
  107. end;
  108. procedure TNewStaticText.CMDialogChar(var Message: TCMDialogChar);
  109. begin
  110. if (FFocusControl <> nil) and Enabled and ShowAccelChar and
  111. IsAccel(Message.CharCode, Caption) then
  112. with FFocusControl do
  113. if CanFocus then
  114. begin
  115. SetFocus;
  116. Message.Result := 1;
  117. end;
  118. end;
  119. procedure TNewStaticText.CMFontChanged(var Message: TMessage);
  120. begin
  121. inherited;
  122. AdjustBounds;
  123. end;
  124. procedure TNewStaticText.CMParentFontChanged(var Message: TMessage);
  125. begin
  126. inherited;
  127. { What we're really trapping here is changes to Parent. Recalculate size
  128. if the new Parent's RTL setting is different. }
  129. if IsParentRightToLeft(Self) <> FLastAdjustBoundsRTL then
  130. AdjustBounds;
  131. end;
  132. procedure TNewStaticText.CMTextChanged(var Message: TMessage);
  133. begin
  134. inherited;
  135. Invalidate;
  136. AdjustBounds;
  137. end;
  138. procedure TNewStaticText.Loaded;
  139. begin
  140. inherited Loaded;
  141. AdjustBounds;
  142. end;
  143. function TNewStaticText.GetDrawTextFlags: UINT;
  144. begin
  145. Result := DT_EXPANDTABS or DT_NOCLIP;
  146. if FWordWrap then Result := Result or DT_WORDBREAK;
  147. if not FShowAccelChar then Result := Result or DT_NOPREFIX;
  148. if IsParentRightToLeft(Self) then begin
  149. { Note: DT_RTLREADING must be included even when just calculating the
  150. size, since on certain fonts it can affect the width of characters.
  151. (Consider the Hebrew string: 'a '#$F9' b'. On 2000 with Lucida Console
  152. as the font, the spaces aren't drawn as wide with RTLREADING.) }
  153. Result := Result or DT_RIGHT;
  154. if not FForceLTRReading then
  155. Result := Result or DT_RTLREADING;
  156. end;
  157. end;
  158. function TNewStaticText.CalcBounds: TPoint;
  159. var
  160. R: TRect;
  161. S: String;
  162. DC: HDC;
  163. begin
  164. { Note: The calculated width/height is actually one pixel wider/taller
  165. than the size of the text, so that when Enabled=False the white shadow
  166. does not get clipped }
  167. R := Rect(0, 0, Width, 0);
  168. if R.Right > 0 then Dec(R.Right);
  169. S := Caption;
  170. if (S = '') or (FShowAccelChar and (S[1] = '&') and (S[2] = #0)) then
  171. S := S + ' ';
  172. DC := GetDC(0);
  173. try
  174. SelectObject(DC, Font.Handle);
  175. DrawText(DC, PChar(S), Length(S), R, DT_CALCRECT or GetDrawTextFlags);
  176. finally
  177. ReleaseDC(0, DC);
  178. end;
  179. Result.X := R.Right + 1;
  180. Result.Y := R.Bottom + 1;
  181. end;
  182. procedure TNewStaticText.AdjustBounds;
  183. var
  184. NewBounds: TPoint;
  185. NewLeft, NewWidth: Integer;
  186. begin
  187. if not (csLoading in ComponentState) and FAutoSize then
  188. begin
  189. FLastAdjustBoundsRTL := IsParentRightToLeft(Self);
  190. NewBounds := CalcBounds;
  191. NewLeft := Left;
  192. NewWidth := Width;
  193. if not FWordWrap then begin
  194. NewWidth := NewBounds.X;
  195. if IsParentFlipped(Self) then
  196. Inc(NewLeft, Width - NewWidth);
  197. end;
  198. SetBounds(NewLeft, Top, NewWidth, NewBounds.Y);
  199. end;
  200. end;
  201. function TNewStaticText.AdjustHeight: Integer;
  202. var
  203. OldHeight: Integer;
  204. begin
  205. OldHeight := Height;
  206. Height := CalcBounds.Y;
  207. Result := Height - OldHeight;
  208. end;
  209. procedure TNewStaticText.Notification(AComponent: TComponent;
  210. Operation: TOperation);
  211. begin
  212. inherited Notification(AComponent, Operation);
  213. if (Operation = opRemove) and (AComponent = FFocusControl) then
  214. FFocusControl := nil;
  215. end;
  216. procedure TNewStaticText.SetAutoSize(Value: Boolean);
  217. begin
  218. if FAutoSize <> Value then
  219. begin
  220. FAutoSize := Value;
  221. if Value then AdjustBounds;
  222. end;
  223. end;
  224. procedure TNewStaticText.SetFocusControl(Value: TWinControl);
  225. begin
  226. FFocusControl := Value;
  227. if Value <> nil then Value.FreeNotification(Self);
  228. end;
  229. procedure TNewStaticText.SetForceLTRReading(Value: Boolean);
  230. begin
  231. if FForceLTRReading <> Value then begin
  232. FForceLTRReading := Value;
  233. RecreateWnd;
  234. AdjustBounds;
  235. end;
  236. end;
  237. procedure TNewStaticText.SetShowAccelChar(Value: Boolean);
  238. begin
  239. if FShowAccelChar <> Value then
  240. begin
  241. FShowAccelChar := Value;
  242. RecreateWnd;
  243. AdjustBounds;
  244. end;
  245. end;
  246. procedure TNewStaticText.SetWordWrap(Value: Boolean);
  247. begin
  248. if FWordWrap <> Value then
  249. begin
  250. FWordWrap := Value;
  251. RecreateWnd;
  252. AdjustBounds;
  253. end;
  254. end;
  255. end.