Guest User

Untitled

a guest
Mar 23rd, 2018
101
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.08 KB | None | 0 0
  1. unit uRichEditExtended;
  2.  
  3. interface
  4. uses
  5. Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, RichEdit, WinApi.ShellApi, Vcl.Controls, Vcl.ComCtrls,
  6. Generics.Collections;
  7.  
  8. type
  9. TZ_RichEditClickEvent = reference to procedure(const ALinkText: string);
  10.  
  11. TZ_RichEditLink = class
  12. IsDefaultEvent: boolean;
  13. Text: string;
  14. OnLinkClickEvent: TZ_RichEditClickEvent;
  15. end;
  16.  
  17. TZ_RichEditLinks = TList<TZ_RichEditLink>;
  18.  
  19. TRichEditExtended = class
  20. protected
  21. class var FInstance: TRichEditExtended;
  22. private
  23. FPrevRichEditWndProc: TWndMethod;
  24. FRichEdit: TRichEdit;
  25. FRichEditLinks: TZ_RichEditLinks;
  26. procedure InsertLinkText(const LinkText: string; SelStart: integer = -1);
  27. procedure SetRichEditMasks;
  28. procedure RichEditWndProc(var Message: TMessage);
  29. procedure AfterConstruction; override;
  30. procedure BeforeDestruction; override;
  31. public
  32. class function This: TRichEditExtended;
  33. class procedure ApplyRichEdit(ARichEdit: TRichEdit); // -1 - вставка в конец текста, иначе в позицию указанную в SelStart без сдвига
  34. class function AddLinkText(AText: string; AOnLinkClickEvent: TZ_RichEditClickEvent; SelStart: integer = -1): integer;
  35. class function AddLinkTextWithDefaultEvent(AText: string; SelStart: integer = -1): integer;
  36. class procedure AddDefaultLinkTextEvent(AOnLinkClickEvent: TZ_RichEditClickEvent);
  37. end;
  38.  
  39. implementation
  40.  
  41. { TRichEditExtended }
  42. uses StrUtils;
  43.  
  44. class procedure TRichEditExtended.AddDefaultLinkTextEvent(AOnLinkClickEvent: TZ_RichEditClickEvent);
  45. var
  46. REL: TZ_RichEditLink;
  47. begin
  48. if (This.FRichEditLinks.Count > 0) and This.FRichEditLinks[0].IsDefaultEvent then
  49. This.FRichEditLinks[0].OnLinkClickEvent := AOnLinkClickEvent
  50. else
  51. begin
  52. REL := TZ_RichEditLink.Create;
  53. REL.IsDefaultEvent := true;
  54. REL.Text := '';
  55. REL.OnLinkClickEvent := AOnLinkClickEvent;
  56. This.FRichEditLinks.Insert(0, REL);
  57. REL := nil;
  58. end;
  59. end;
  60.  
  61. class function TRichEditExtended.AddLinkText(AText: string; AOnLinkClickEvent: TZ_RichEditClickEvent; SelStart: integer = -1): integer;
  62. var REL: TZ_RichEditLink;
  63. begin
  64. REL := TZ_RichEditLink.Create;
  65. REL.IsDefaultEvent := false;
  66. REL.Text := AText;
  67. REL.OnLinkClickEvent := AOnLinkClickEvent;
  68. Result := This.FRichEditLinks.Add(REL);
  69. This.InsertLinkText(AText, SelStart);
  70. REL := nil;
  71. end;
  72.  
  73. class function TRichEditExtended.AddLinkTextWithDefaultEvent(AText: string; SelStart: integer): integer;
  74. begin
  75. This.AddLinkText(AText, nil, SelStart);
  76. end;
  77.  
  78. procedure TRichEditExtended.AfterConstruction;
  79. begin
  80. inherited;
  81. FRichEdit := nil;
  82. FRichEditLinks := TZ_RichEditLinks.Create;
  83. end;
  84.  
  85. class procedure TRichEditExtended.ApplyRichEdit(ARichEdit: TRichEdit);
  86. begin
  87. This.FRichEdit := ARichEdit;
  88. This.FPrevRichEditWndProc := This.FRichEdit.WindowProc;
  89. This.FRichEdit.WindowProc := This.RichEditWndProc;
  90. This.FRichEditLinks.Clear;
  91. This.SetRichEditMasks;
  92. end;
  93.  
  94. procedure TRichEditExtended.BeforeDestruction;
  95. begin
  96. if Assigned(FRichEdit) then
  97. FRichEdit.WindowProc := FPrevRichEditWndProc;
  98. FRichEdit := nil;
  99. FRichEditLinks.Clear;
  100. FRichEditLinks.Free;
  101. inherited;
  102. end;
  103.  
  104. procedure TRichEditExtended.InsertLinkText(const LinkText: string; SelStart: integer = -1);
  105. var
  106. Fmt: CHARFORMAT2;
  107. begin
  108. if SelStart = -1 then
  109. begin
  110. SelStart := FRichEdit.Lines.Text.Length - 1;
  111. FRichEdit.Text := FRichEdit.Text + LinkText;
  112. dec(SelStart,2 * (FRichEdit.Lines.Text.CountChar(#$D) - 1));
  113. end
  114. else
  115. begin
  116. FRichEdit.SelStart := SelStart;
  117. FRichEdit.SelText := LinkText;
  118. end;
  119. FRichEdit.SelStart := SelStart;
  120. FRichEdit.SelLength := Length(LinkText);
  121.  
  122. FillChar(Fmt, SizeOf(Fmt), 0);
  123. Fmt.cbSize := SizeOf(Fmt);
  124. Fmt.dwMask := CFM_LINK;
  125. Fmt.dwEffects := CFE_LINK;
  126.  
  127. SendMessage(FRichEdit.Handle, EM_SETCHARFORMAT, SCF_SELECTION, LPARAM(@Fmt));
  128.  
  129. FRichEdit.SelStart := SelStart + Length(LinkText);
  130. FRichEdit.SelLength := 0;
  131. end;
  132.  
  133. procedure TRichEditExtended.RichEditWndProc(var Message: TMessage);
  134. type
  135. PENLINK = ^ENLINK;
  136. var
  137. tr: TEXTRANGE;
  138. str: string;
  139. p: PENLINK;
  140. i: integer;
  141. begin
  142. FPrevRichEditWndProc(Message);
  143.  
  144. case Message.Msg of
  145. CN_NOTIFY: begin
  146. if TWMNotify(Message).NMHdr.code = EN_LINK then
  147. begin
  148. P := PENLINK(Message.LParam);
  149. if p.msg = WM_LBUTTONDOWN then
  150. begin
  151. SetLength(str, p.chrg.cpMax - p.chrg.cpMin);
  152. tr.chrg := p.chrg;
  153. tr.lpstrText := PChar(str);
  154. SendMessage(FRichEdit.Handle, EM_GETTEXTRANGE, 0, LPARAM(@tr));
  155.  
  156. for I := 0 to FRichEditLinks.Count - 1 do
  157. if str.ToUpper.Equals(FRichEditLinks[I].Text.ToUpper) then
  158. begin
  159. if not Assigned(FRichEditLinks[I].OnLinkClickEvent) then
  160. begin
  161. if not FRichEditLinks[0].IsDefaultEvent then
  162. raise Exception.Create('No default event is set.')
  163. else
  164. FRichEditLinks[0].OnLinkClickEvent(str)
  165. end
  166. else
  167. FRichEditLinks[I].OnLinkClickEvent(str);
  168. exit;
  169. end;
  170. end;
  171. end;
  172. end;
  173.  
  174. CM_RECREATEWND: begin
  175. SetRichEditMasks;
  176. end;
  177. end;
  178. end;
  179.  
  180. procedure TRichEditExtended.SetRichEditMasks;
  181. var
  182. Mask: DWORD;
  183. begin
  184. Mask := SendMessage(FRichEdit.Handle, EM_GETEVENTMASK, 0, 0);
  185. SendMessage(FRichEdit.Handle, EM_SETEVENTMASK, 0, Mask or ENM_LINK);
  186. SendMessage(FRichEdit.Handle, EM_AUTOURLDETECT, 1, 0);
  187. end;
  188.  
  189. class function TRichEditExtended.This: TRichEditExtended;
  190. begin
  191. if not Assigned(TRichEditExtended.FInstance) then
  192. TRichEditExtended.FInstance := TRichEditExtended.Create;
  193. Result := TRichEditExtended.FInstance;
  194. end;
  195.  
  196. { TRichEditExList }
  197.  
  198. initialization
  199.  
  200. finalization
  201. if Assigned(TRichEditExtended.FInstance) then
  202. TRichEditExtended.FInstance.Free;
  203.  
  204. end.
  205.  
  206. TRichEditExtended.ApplyRichEdit(ed1);
  207. TRichEditExtended.AddDefaultLinkTextEvent(procedure (const T: String)begin showmessage(T); end);
  208. TRichEditExtended.AddLinkTextWithDefaultEvent('Link');
  209. ed1.Text := ed1.Text + '1231232 ';
  210. TRichEditExtended.AddLinkTextWithDefaultEvent('Link2');
Add Comment
Please, Sign In to add comment