viewOverlays.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. import { createFastDomNode } from '../../../base/browser/fastDomNode.js';
  6. import { Configuration } from '../config/configuration.js';
  7. import { VisibleLinesCollection } from './viewLayer.js';
  8. import { ViewPart } from './viewPart.js';
  9. export class ViewOverlays extends ViewPart {
  10. constructor(context) {
  11. super(context);
  12. this._visibleLines = new VisibleLinesCollection(this);
  13. this.domNode = this._visibleLines.domNode;
  14. this._dynamicOverlays = [];
  15. this._isFocused = false;
  16. this.domNode.setClassName('view-overlays');
  17. }
  18. shouldRender() {
  19. if (super.shouldRender()) {
  20. return true;
  21. }
  22. for (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {
  23. const dynamicOverlay = this._dynamicOverlays[i];
  24. if (dynamicOverlay.shouldRender()) {
  25. return true;
  26. }
  27. }
  28. return false;
  29. }
  30. dispose() {
  31. super.dispose();
  32. for (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {
  33. const dynamicOverlay = this._dynamicOverlays[i];
  34. dynamicOverlay.dispose();
  35. }
  36. this._dynamicOverlays = [];
  37. }
  38. getDomNode() {
  39. return this.domNode;
  40. }
  41. // ---- begin IVisibleLinesHost
  42. createVisibleLine() {
  43. return new ViewOverlayLine(this._context.configuration, this._dynamicOverlays);
  44. }
  45. // ---- end IVisibleLinesHost
  46. addDynamicOverlay(overlay) {
  47. this._dynamicOverlays.push(overlay);
  48. }
  49. // ----- event handlers
  50. onConfigurationChanged(e) {
  51. this._visibleLines.onConfigurationChanged(e);
  52. const startLineNumber = this._visibleLines.getStartLineNumber();
  53. const endLineNumber = this._visibleLines.getEndLineNumber();
  54. for (let lineNumber = startLineNumber; lineNumber <= endLineNumber; lineNumber++) {
  55. const line = this._visibleLines.getVisibleLine(lineNumber);
  56. line.onConfigurationChanged(e);
  57. }
  58. return true;
  59. }
  60. onFlushed(e) {
  61. return this._visibleLines.onFlushed(e);
  62. }
  63. onFocusChanged(e) {
  64. this._isFocused = e.isFocused;
  65. return true;
  66. }
  67. onLinesChanged(e) {
  68. return this._visibleLines.onLinesChanged(e);
  69. }
  70. onLinesDeleted(e) {
  71. return this._visibleLines.onLinesDeleted(e);
  72. }
  73. onLinesInserted(e) {
  74. return this._visibleLines.onLinesInserted(e);
  75. }
  76. onScrollChanged(e) {
  77. return this._visibleLines.onScrollChanged(e) || true;
  78. }
  79. onTokensChanged(e) {
  80. return this._visibleLines.onTokensChanged(e);
  81. }
  82. onZonesChanged(e) {
  83. return this._visibleLines.onZonesChanged(e);
  84. }
  85. // ----- end event handlers
  86. prepareRender(ctx) {
  87. const toRender = this._dynamicOverlays.filter(overlay => overlay.shouldRender());
  88. for (let i = 0, len = toRender.length; i < len; i++) {
  89. const dynamicOverlay = toRender[i];
  90. dynamicOverlay.prepareRender(ctx);
  91. dynamicOverlay.onDidRender();
  92. }
  93. }
  94. render(ctx) {
  95. // Overwriting to bypass `shouldRender` flag
  96. this._viewOverlaysRender(ctx);
  97. this.domNode.toggleClassName('focused', this._isFocused);
  98. }
  99. _viewOverlaysRender(ctx) {
  100. this._visibleLines.renderLines(ctx.viewportData);
  101. }
  102. }
  103. export class ViewOverlayLine {
  104. constructor(configuration, dynamicOverlays) {
  105. this._configuration = configuration;
  106. this._lineHeight = this._configuration.options.get(58 /* lineHeight */);
  107. this._dynamicOverlays = dynamicOverlays;
  108. this._domNode = null;
  109. this._renderedContent = null;
  110. }
  111. getDomNode() {
  112. if (!this._domNode) {
  113. return null;
  114. }
  115. return this._domNode.domNode;
  116. }
  117. setDomNode(domNode) {
  118. this._domNode = createFastDomNode(domNode);
  119. }
  120. onContentChanged() {
  121. // Nothing
  122. }
  123. onTokensChanged() {
  124. // Nothing
  125. }
  126. onConfigurationChanged(e) {
  127. this._lineHeight = this._configuration.options.get(58 /* lineHeight */);
  128. }
  129. renderLine(lineNumber, deltaTop, viewportData, sb) {
  130. let result = '';
  131. for (let i = 0, len = this._dynamicOverlays.length; i < len; i++) {
  132. const dynamicOverlay = this._dynamicOverlays[i];
  133. result += dynamicOverlay.render(viewportData.startLineNumber, lineNumber);
  134. }
  135. if (this._renderedContent === result) {
  136. // No rendering needed
  137. return false;
  138. }
  139. this._renderedContent = result;
  140. sb.appendASCIIString('<div style="position:absolute;top:');
  141. sb.appendASCIIString(String(deltaTop));
  142. sb.appendASCIIString('px;width:100%;height:');
  143. sb.appendASCIIString(String(this._lineHeight));
  144. sb.appendASCIIString('px;">');
  145. sb.appendASCIIString(result);
  146. sb.appendASCIIString('</div>');
  147. return true;
  148. }
  149. layoutLine(lineNumber, deltaTop) {
  150. if (this._domNode) {
  151. this._domNode.setTop(deltaTop);
  152. this._domNode.setHeight(this._lineHeight);
  153. }
  154. }
  155. }
  156. export class ContentViewOverlays extends ViewOverlays {
  157. constructor(context) {
  158. super(context);
  159. const options = this._context.configuration.options;
  160. const layoutInfo = options.get(130 /* layoutInfo */);
  161. this._contentWidth = layoutInfo.contentWidth;
  162. this.domNode.setHeight(0);
  163. }
  164. // --- begin event handlers
  165. onConfigurationChanged(e) {
  166. const options = this._context.configuration.options;
  167. const layoutInfo = options.get(130 /* layoutInfo */);
  168. this._contentWidth = layoutInfo.contentWidth;
  169. return super.onConfigurationChanged(e) || true;
  170. }
  171. onScrollChanged(e) {
  172. return super.onScrollChanged(e) || e.scrollWidthChanged;
  173. }
  174. // --- end event handlers
  175. _viewOverlaysRender(ctx) {
  176. super._viewOverlaysRender(ctx);
  177. this.domNode.setWidth(Math.max(ctx.scrollWidth, this._contentWidth));
  178. }
  179. }
  180. export class MarginViewOverlays extends ViewOverlays {
  181. constructor(context) {
  182. super(context);
  183. const options = this._context.configuration.options;
  184. const layoutInfo = options.get(130 /* layoutInfo */);
  185. this._contentLeft = layoutInfo.contentLeft;
  186. this.domNode.setClassName('margin-view-overlays');
  187. this.domNode.setWidth(1);
  188. Configuration.applyFontInfo(this.domNode, options.get(43 /* fontInfo */));
  189. }
  190. onConfigurationChanged(e) {
  191. const options = this._context.configuration.options;
  192. Configuration.applyFontInfo(this.domNode, options.get(43 /* fontInfo */));
  193. const layoutInfo = options.get(130 /* layoutInfo */);
  194. this._contentLeft = layoutInfo.contentLeft;
  195. return super.onConfigurationChanged(e) || true;
  196. }
  197. onScrollChanged(e) {
  198. return super.onScrollChanged(e) || e.scrollHeightChanged;
  199. }
  200. _viewOverlaysRender(ctx) {
  201. super._viewOverlaysRender(ctx);
  202. const height = Math.min(ctx.scrollHeight, 1000000);
  203. this.domNode.setHeight(height);
  204. this.domNode.setWidth(this._contentLeft);
  205. }
  206. }