LineNumbersMemoFMX.pas 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. unit LineNumbersMemoFMX;
  2. interface
  3. uses
  4. FMX.TextLayout, FMX.Text.LinesLayout, FMX.Memo.Style.New, System.Math,
  5. System.SysUtils, System.Types, System.UITypes, System.Classes, FMX.Memo, FMX.Layouts,
  6. FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.StdCtrls, FMX.Objects;
  7. type
  8. TLinesMemoUtil = class(TComponent)
  9. private
  10. FStyleMemo: TStyledMemo;
  11. FLinesLayout: TLinesLayout;
  12. FRectangle: TRectangle;
  13. FMemo: TMemo;
  14. FFontColor: TAlphaColor;
  15. FFontColorCurrentLine: TAlphaColor;
  16. FFontSize: Single;
  17. FLineColor: TAlphaColor;
  18. FRectWidth: Single;
  19. FOldOnViewportPositionChange: TPositionChangeEvent;
  20. procedure SetMemo(const AValue: TMemo);
  21. procedure SetFontColor(AValue: TAlphaColor);
  22. procedure SetFontColorCurrentLine(AValue: TAlphaColor);
  23. procedure SetLineColor(AValue: TAlphaColor);
  24. procedure SetFontSize(AValue: Single);
  25. procedure SetRectWidth(AValue: Single);
  26. procedure ApplyStyleLookup(Sender: TObject);
  27. procedure LineNumberPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
  28. procedure MemoViewportPositionChange(Sender: TObject; const OldViewportPosition, NewViewportPosition: TPointF; const ContentSizeChanged: Boolean);
  29. public
  30. property Memo: TMemo read FMemo write SetMemo;
  31. property FontColor: TAlphaColor read FFontColor write SetFontColor;
  32. property FontColorCurrentLine: TAlphaColor read FFontColorCurrentLine write SetFontColorCurrentLine;
  33. property LineColor: TAlphaColor read FLineColor write SetLineColor;
  34. property FontSize: Single read FFontSize write SetFontSize;
  35. property RectWidth: Single read FRectWidth write SetRectWidth;
  36. public
  37. constructor Create(AOwner: TComponent); overload; override;
  38. constructor Create(AOwner: TComponent; AMemo: TMemo); reintroduce; overload;
  39. destructor Destroy; override;
  40. end;
  41. implementation
  42. uses Logger;
  43. constructor TLinesMemoUtil.Create(AOwner: TComponent);
  44. begin
  45. inherited;
  46. FStyleMemo := nil;
  47. FFontColorCurrentLine := $FF33CC33;
  48. FFontColor := $FF808080;
  49. FFontSize := 11;
  50. FLineColor := $80808080;
  51. FRectWidth := 40;
  52. FOldOnViewportPositionChange := nil;
  53. end;
  54. constructor TLinesMemoUtil.Create(AOwner: TComponent; AMemo: TMemo);
  55. begin
  56. Create(AOwner);
  57. SetMemo(AMemo);
  58. end;
  59. destructor TLinesMemoUtil.Destroy;
  60. begin
  61. inherited;
  62. end;
  63. procedure TLinesMemoUtil.SetMemo(const AValue: TMemo);
  64. begin
  65. if FMemo = AValue then
  66. Exit;
  67. FMemo := AValue;
  68. FMemo.OnApplyStyleLookup := ApplyStyleLookup;
  69. FOldOnViewportPositionChange := FMemo.OnViewportPositionChange;
  70. FMemo.OnViewportPositionChange := MemoViewportPositionChange;
  71. if FStyleMemo = nil then
  72. begin
  73. FMemo.EnumObjects(
  74. function(obj: TFmxObject): TEnumProcResult
  75. begin
  76. if obj is TStyledMemo then
  77. begin
  78. FStyleMemo := TStyledMemo(obj);
  79. FLinesLayout := FStyleMemo.Editor.LinesLayout;
  80. Result := TEnumProcResult.Stop;
  81. end
  82. else
  83. begin
  84. Result := TEnumProcResult.Continue;
  85. end;
  86. end);
  87. end;
  88. end;
  89. procedure TLinesMemoUtil.SetFontColor(AValue: TAlphaColor);
  90. begin
  91. if FFontColor = AValue then
  92. Exit;
  93. FFontColor := AValue;
  94. FRectangle.Repaint;
  95. end;
  96. procedure TLinesMemoUtil.SetFontColorCurrentLine(AValue: TAlphaColor);
  97. begin
  98. if FFontColorCurrentLine = AValue then
  99. Exit;
  100. FFontColorCurrentLine := AValue;
  101. FRectangle.Repaint;
  102. end;
  103. procedure TLinesMemoUtil.SetLineColor(AValue: TAlphaColor);
  104. begin
  105. if FLineColor = AValue then
  106. Exit;
  107. FLineColor := AValue;
  108. FRectangle.Stroke.Color := FLineColor;
  109. end;
  110. procedure TLinesMemoUtil.SetFontSize(AValue: Single);
  111. begin
  112. if FFontSize = AValue then
  113. Exit;
  114. FFontSize := AValue;
  115. FRectangle.Repaint;
  116. end;
  117. procedure TLinesMemoUtil.SetRectWidth(AValue: Single);
  118. begin
  119. if FRectWidth = AValue then
  120. Exit;
  121. FRectWidth := AValue;
  122. FRectangle.Width := AValue;
  123. FMemo.RecalcSize;
  124. end;
  125. procedure TLinesMemoUtil.ApplyStyleLookup(Sender: TObject);
  126. var
  127. resContent: TFmxObject;
  128. begin
  129. resContent := TFmxObject(Sender).FindStyleResource('content');
  130. if resContent <> nil then
  131. begin
  132. FRectangle := TRectangle.Create(nil);
  133. FRectangle.HitTest := False;
  134. FRectangle.ClipChildren := True;
  135. FRectangle.Sides := [TSide.Right];
  136. FRectangle.OnPaint := LineNumberPaint;
  137. FRectangle.Fill.Kind := TBrushKind.None;
  138. FRectangle.Stroke.Color := FLineColor;
  139. FRectangle.Width := FRectWidth;
  140. FRectangle.Align := TAlignLayout.Left;
  141. FRectangle.StyleName := 'lines';
  142. FRectangle.Margins.Rect := RectF(0, TControl(resContent).Margins.Top, 0, TControl(resContent).Margins.Bottom);
  143. resContent.Parent.AddObject(FRectangle);
  144. FRectangle.BringToFront;
  145. end;
  146. end;
  147. procedure TLinesMemoUtil.LineNumberPaint(Sender: TObject; Canvas: TCanvas; const ARect: TRectF);
  148. var
  149. LRect: TRectF;
  150. begin
  151. Canvas.BeginScene;
  152. try
  153. Canvas.Font.Size := FFontSize;
  154. for var i := Max(0, FLinesLayout.FirstVisibleLineIndex) to Min(FLinesLayout.LastVisibleLineIndex, FStyleMemo.Editor.LinesLayout.Count - 1) do
  155. begin
  156. LRect := RectF(ARect.Left, FLinesLayout[i].Rect.Top - FMemo.ViewportPosition.Y, ARect.Right - 2, FLinesLayout[i].Rect.Bottom - FMemo.ViewportPosition.Y);
  157. if i = FMemo.CaretPosition.Line then
  158. begin
  159. Canvas.Fill.Color := $FF808080;
  160. Canvas.FillRect(LRect, 0.2);
  161. Canvas.Fill.Color := FFontColorCurrentLine;
  162. end
  163. else
  164. begin
  165. Canvas.Fill.Color := FFontColor;
  166. end;
  167. Canvas.FillText(LRect, IntToStr(i + 1), False, 1.0, [], TTextAlign.Center, TTextAlign.Center);
  168. end;
  169. finally
  170. Canvas.EndScene;
  171. end;
  172. end;
  173. procedure TLinesMemoUtil.MemoViewportPositionChange(Sender: TObject; const OldViewportPosition, NewViewportPosition: TPointF; const ContentSizeChanged: Boolean);
  174. begin
  175. FRectangle.Repaint;
  176. if Assigned(FOldOnViewportPositionChange) then
  177. begin
  178. FOldOnViewportPositionChange(Sender, OldViewportPosition, NewViewportPosition, ContentSizeChanged);
  179. end;
  180. end;
  181. end.