drawing.inc 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. {
  2. $Id$
  3. "SHEdit" - Text editor with syntax highlighting
  4. Copyright (C) 1999-2000 by Sebastian Guenther ([email protected])
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. }
  11. // Drawing code of TSHTextEdit (renderer for syntax highlighting engine);
  12. // also handles cursor drawing
  13. procedure TSHTextEdit.DoHighlighting(var flags: Byte; source, dest: PChar);
  14. begin
  15. StrCopy(dest, source);
  16. end;
  17. function TSHTextEdit.CalcSHFlags(FlagsIn: Byte; source: String): Byte;
  18. var
  19. s: PChar;
  20. flags: Byte;
  21. begin
  22. GetMem(s, Length(source) * 3 + 4);
  23. flags := FlagsIn;
  24. DoHighlighting(flags, PChar(source), s);
  25. FreeMem(s, Length(source) * 3 + 4);
  26. Result := flags;
  27. end;
  28. procedure TSHTextEdit.HideCursor;
  29. begin
  30. Dec(CursorVisible);
  31. if CursorVisible >= 0 then
  32. FWidget.HideCursor(CursorX, CursorY);
  33. end;
  34. procedure TSHTextEdit.ShowCursor;
  35. begin
  36. Inc(CursorVisible);
  37. if CursorVisible = 1 then
  38. FWidget.ShowCursor(CursorX, CursorY);
  39. end;
  40. procedure TSHTextEdit.ChangeInLine(line: Integer);
  41. var
  42. CurLine: Integer;
  43. OldFlags, NewFlags: Byte;
  44. begin
  45. // Determine how many lines must be redrawn
  46. CurLine := line;
  47. if CurLine = 0 then
  48. NewFlags := 0
  49. else
  50. NewFlags := FDoc.LineFlags[CurLine - 1];
  51. while CurLine < FDoc.LineCount - 1 do begin
  52. NewFlags := CalcSHFlags(NewFlags, FDoc.LineText[CurLine]);
  53. OldFlags := FDoc.LineFlags[CurLine + 1] and not LF_SH_Valid;
  54. FDoc.LineFlags[CurLine + 1] := NewFlags or LF_SH_Valid;
  55. if OldFlags = (NewFlags and not LF_SH_Valid) then break;
  56. Inc(CurLine);
  57. end;
  58. // Redraw all lines with changed SH flags
  59. FWidget.InvalidateRect(FWidget.HorzPos, line, FWidget.PageWidth, (CurLine - line) + 1);
  60. end;
  61. procedure TSHTextEdit.DrawContent(x, y, w, h: Integer);
  62. var
  63. x2, y2: Integer;
  64. procedure PostprocessOutput(py: Integer);
  65. begin
  66. // Erase free space below the text area
  67. if py < y2 then
  68. FWidget.ClearRect(x, py, w, y2 - py);
  69. if (FCursorX >= x) and (FCursorY >= y) and
  70. (FCursorX <= x2) and (FCursorY <= y2) then
  71. ShowCursor;
  72. end;
  73. // If Lenght(s) < x, add as many spaces to s so that x will be at
  74. // the end of s.
  75. procedure ProvideSpace(var s: String; x: Integer);
  76. begin
  77. while Length(s) < x do
  78. s := s + ' ';
  79. end;
  80. var
  81. i, cx, LineNumber, CheckLine: Integer;
  82. OrigStr, s, s2: PChar;
  83. spos, smem: Integer;
  84. flags: Byte;
  85. InSel: Boolean;
  86. LastCol: Char;
  87. LineWithSpace: String; // used for virtual whitespace expanding
  88. begin
  89. if x < 0 then begin
  90. Inc(w, x);
  91. x := 0;
  92. end;
  93. if y < 0 then begin
  94. Inc(h, y);
  95. y := 0;
  96. end;
  97. if (w < 0) or (h < 0) then exit;
  98. x2 := x + w;
  99. y2 := y + h;
  100. if (FCursorX >= x) and (FCursorY >= y) and
  101. (FCursorX <= x2) and (FCursorY <= y2) then
  102. //HideCursor;
  103. Dec(CursorVisible);
  104. if (FDoc = nil) or (FDoc.LineCount <= y) then begin
  105. PostprocessOutput(y);
  106. exit;
  107. end;
  108. LineNumber := y;
  109. // Check if syntax highlighting flags are valid:
  110. if (FDoc.LineFlags[LineNumber] and LF_SH_Valid) <> 0 then
  111. flags := FDoc.LineFlags[LineNumber] and not LF_SH_Valid
  112. else begin
  113. // search for last valid line before the first line to be drawn
  114. CheckLine := LineNumber;
  115. while (CheckLine >= 0) and
  116. ((FDoc.LineFlags[CheckLine] and LF_SH_Valid) = 0) do Dec(CheckLine);
  117. if CheckLine >= 0 then begin
  118. flags := FDoc.LineFlags[CheckLine] and not LF_SH_Valid;
  119. // Recalc SH flags for all lines between last valid and first visible line
  120. while (CheckLine < LineNumber) do begin
  121. flags := CalcSHFlags(flags, FDoc.LineText[CheckLine]);
  122. FDoc.LineFlags[CheckLine] := flags or LF_SH_Valid;
  123. Inc(CheckLine);
  124. end;
  125. end else
  126. flags := 0;
  127. end;
  128. // if FSel.IsValid then writeln('Selection: ',FSel.OStartX,',',FSel.OStartY,'-',FSel.OEndX,',',FSel.OEndY);
  129. while (LineNumber < FDoc.LineCount) and (LineNumber <= y2) do begin
  130. i := 0;
  131. // Do virtual whitespace expanding
  132. LineWithSpace := FDoc.LineText[LineNumber];
  133. if LineNumber = FSel.OStartY then
  134. ProvideSpace(LineWithSpace, FSel.OStartX);
  135. if LineNumber = FSel.OEndY then
  136. ProvideSpace(LineWithSpace, FSel.OEndX);
  137. if LineNumber = FCursorY then
  138. ProvideSpace(LineWithSpace, FCursorX);
  139. // Call syntax highlighter for this line
  140. smem := Length(LineWithSpace) * 3 + 8;
  141. GetMem(s, smem);
  142. FDoc.LineFlags[LineNumber] := flags or LF_SH_Valid;
  143. OrigStr := PChar(LineWithSpace);
  144. DoHighlighting(flags, OrigStr, s);
  145. // Handle current selection
  146. if FSel.IsValid then
  147. if (LineNumber > FSel.OStartY) and (LineNumber < FSel.OEndY) then begin
  148. ASSERT(smem > StrLen(OrigStr) + 2);
  149. s[0] := LF_Escape;
  150. s[1] := Chr(shSelected);
  151. StrCopy(@s[2], OrigStr);
  152. end else if OrigStr[0] = #0 then begin
  153. if LineNumber = FSel.OStartY then begin
  154. ASSERT(smem >= 3);
  155. s[0] := LF_Escape;
  156. s[1] := Chr(shSelected);
  157. s[2] := #0;
  158. end;
  159. end else if ((LineNumber = FSel.OStartY) or (LineNumber = FSel.OEndY))
  160. and not FSel.IsEmpty then begin
  161. s2 := StrNew(s);
  162. spos := 0;
  163. i := 0;
  164. cx := 0;
  165. if LineNumber > FSel.OStartY then begin
  166. ASSERT(smem >= 2);
  167. s[0] := LF_Escape;
  168. s[1] := Chr(shSelected);
  169. InSel := True;
  170. spos := 2;
  171. end else
  172. InSel := False;
  173. LastCol := Chr(shDefault);
  174. while True do begin
  175. ASSERT(i <= StrLen(s2));
  176. if s2[i] = LF_Escape then begin
  177. LastCol := s2[i + 1];
  178. if not InSel then begin
  179. ASSERT(smem > spos + 1);
  180. s[spos] := LF_Escape;
  181. s[spos + 1] := LastCol;
  182. Inc(spos, 2);
  183. end;
  184. Inc(i, 2);
  185. end else begin
  186. if InSel then begin
  187. if (LineNumber = FSel.OEndY) and (cx = FSel.OEndX) then begin
  188. ASSERT(smem > spos + 1);
  189. s[spos] := LF_Escape;
  190. s[spos + 1] := LastCol;
  191. Inc(spos, 2);
  192. InSel := False;
  193. end;
  194. end else
  195. if (LineNumber = FSel.OStartY) and (cx = FSel.OStartX) then begin
  196. ASSERT(smem > spos + 1);
  197. s[spos] := LF_Escape;
  198. s[spos + 1] := Chr(shSelected);
  199. Inc(spos, 2);
  200. InSel := True;
  201. end;
  202. if s2[i] = #0 then break; // only exit of 'while' loop!
  203. ASSERT(smem > spos);
  204. s[spos] := s2[i];
  205. Inc(spos);
  206. Inc(i);
  207. Inc(cx);
  208. end;
  209. end;
  210. ASSERT(smem > spos);
  211. s[spos] := #0;
  212. StrDispose(s2);
  213. end;
  214. FWidget.DrawTextLine(x, x2, LineNumber, s);
  215. FreeMem(s);
  216. Inc(LineNumber);
  217. end;
  218. PostprocessOutput(LineNumber);
  219. end;
  220. {
  221. $Log$
  222. Revision 1.3 2002-09-07 15:15:28 peter
  223. * old logs removed and tabs fixed
  224. }