cbde359985fa2e7130deb8a3d9622c831e5724237fb3d259caf0b1def87d8df8af03d17fb9ac026ee02c0f2eb11daeb7ae8d1cb286bc0f441f191e5fcda368 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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 * as dom from '../../../../base/browser/dom.js';
  6. import { createFastDomNode } from '../../../../base/browser/fastDomNode.js';
  7. import { SmoothScrollableElement } from '../../../../base/browser/ui/scrollbar/scrollableElement.js';
  8. import { PartFingerprints, ViewPart } from '../../view/viewPart.js';
  9. import { registerThemingParticipant, getThemeTypeSelector } from '../../../../platform/theme/common/themeService.js';
  10. import { scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground } from '../../../../platform/theme/common/colorRegistry.js';
  11. export class EditorScrollbar extends ViewPart {
  12. constructor(context, linesContent, viewDomNode, overflowGuardDomNode) {
  13. super(context);
  14. const options = this._context.configuration.options;
  15. const scrollbar = options.get(94 /* EditorOption.scrollbar */);
  16. const mouseWheelScrollSensitivity = options.get(69 /* EditorOption.mouseWheelScrollSensitivity */);
  17. const fastScrollSensitivity = options.get(36 /* EditorOption.fastScrollSensitivity */);
  18. const scrollPredominantAxis = options.get(97 /* EditorOption.scrollPredominantAxis */);
  19. const scrollbarOptions = {
  20. listenOnDomNode: viewDomNode.domNode,
  21. className: 'editor-scrollable' + ' ' + getThemeTypeSelector(context.theme.type),
  22. useShadows: false,
  23. lazyRender: true,
  24. vertical: scrollbar.vertical,
  25. horizontal: scrollbar.horizontal,
  26. verticalHasArrows: scrollbar.verticalHasArrows,
  27. horizontalHasArrows: scrollbar.horizontalHasArrows,
  28. verticalScrollbarSize: scrollbar.verticalScrollbarSize,
  29. verticalSliderSize: scrollbar.verticalSliderSize,
  30. horizontalScrollbarSize: scrollbar.horizontalScrollbarSize,
  31. horizontalSliderSize: scrollbar.horizontalSliderSize,
  32. handleMouseWheel: scrollbar.handleMouseWheel,
  33. alwaysConsumeMouseWheel: scrollbar.alwaysConsumeMouseWheel,
  34. arrowSize: scrollbar.arrowSize,
  35. mouseWheelScrollSensitivity: mouseWheelScrollSensitivity,
  36. fastScrollSensitivity: fastScrollSensitivity,
  37. scrollPredominantAxis: scrollPredominantAxis,
  38. scrollByPage: scrollbar.scrollByPage,
  39. };
  40. this.scrollbar = this._register(new SmoothScrollableElement(linesContent.domNode, scrollbarOptions, this._context.viewLayout.getScrollable()));
  41. PartFingerprints.write(this.scrollbar.getDomNode(), 5 /* PartFingerprint.ScrollableElement */);
  42. this.scrollbarDomNode = createFastDomNode(this.scrollbar.getDomNode());
  43. this.scrollbarDomNode.setPosition('absolute');
  44. this._setLayout();
  45. // When having a zone widget that calls .focus() on one of its dom elements,
  46. // the browser will try desperately to reveal that dom node, unexpectedly
  47. // changing the .scrollTop of this.linesContent
  48. const onBrowserDesperateReveal = (domNode, lookAtScrollTop, lookAtScrollLeft) => {
  49. const newScrollPosition = {};
  50. if (lookAtScrollTop) {
  51. const deltaTop = domNode.scrollTop;
  52. if (deltaTop) {
  53. newScrollPosition.scrollTop = this._context.viewLayout.getCurrentScrollTop() + deltaTop;
  54. domNode.scrollTop = 0;
  55. }
  56. }
  57. if (lookAtScrollLeft) {
  58. const deltaLeft = domNode.scrollLeft;
  59. if (deltaLeft) {
  60. newScrollPosition.scrollLeft = this._context.viewLayout.getCurrentScrollLeft() + deltaLeft;
  61. domNode.scrollLeft = 0;
  62. }
  63. }
  64. this._context.viewModel.viewLayout.setScrollPosition(newScrollPosition, 1 /* ScrollType.Immediate */);
  65. };
  66. // I've seen this happen both on the view dom node & on the lines content dom node.
  67. this._register(dom.addDisposableListener(viewDomNode.domNode, 'scroll', (e) => onBrowserDesperateReveal(viewDomNode.domNode, true, true)));
  68. this._register(dom.addDisposableListener(linesContent.domNode, 'scroll', (e) => onBrowserDesperateReveal(linesContent.domNode, true, false)));
  69. this._register(dom.addDisposableListener(overflowGuardDomNode.domNode, 'scroll', (e) => onBrowserDesperateReveal(overflowGuardDomNode.domNode, true, false)));
  70. this._register(dom.addDisposableListener(this.scrollbarDomNode.domNode, 'scroll', (e) => onBrowserDesperateReveal(this.scrollbarDomNode.domNode, true, false)));
  71. }
  72. dispose() {
  73. super.dispose();
  74. }
  75. _setLayout() {
  76. const options = this._context.configuration.options;
  77. const layoutInfo = options.get(133 /* EditorOption.layoutInfo */);
  78. this.scrollbarDomNode.setLeft(layoutInfo.contentLeft);
  79. const minimap = options.get(67 /* EditorOption.minimap */);
  80. const side = minimap.side;
  81. if (side === 'right') {
  82. this.scrollbarDomNode.setWidth(layoutInfo.contentWidth + layoutInfo.minimap.minimapWidth);
  83. }
  84. else {
  85. this.scrollbarDomNode.setWidth(layoutInfo.contentWidth);
  86. }
  87. this.scrollbarDomNode.setHeight(layoutInfo.height);
  88. }
  89. getOverviewRulerLayoutInfo() {
  90. return this.scrollbar.getOverviewRulerLayoutInfo();
  91. }
  92. getDomNode() {
  93. return this.scrollbarDomNode;
  94. }
  95. delegateVerticalScrollbarPointerDown(browserEvent) {
  96. this.scrollbar.delegateVerticalScrollbarPointerDown(browserEvent);
  97. }
  98. // --- begin event handlers
  99. onConfigurationChanged(e) {
  100. if (e.hasChanged(94 /* EditorOption.scrollbar */)
  101. || e.hasChanged(69 /* EditorOption.mouseWheelScrollSensitivity */)
  102. || e.hasChanged(36 /* EditorOption.fastScrollSensitivity */)) {
  103. const options = this._context.configuration.options;
  104. const scrollbar = options.get(94 /* EditorOption.scrollbar */);
  105. const mouseWheelScrollSensitivity = options.get(69 /* EditorOption.mouseWheelScrollSensitivity */);
  106. const fastScrollSensitivity = options.get(36 /* EditorOption.fastScrollSensitivity */);
  107. const scrollPredominantAxis = options.get(97 /* EditorOption.scrollPredominantAxis */);
  108. const newOpts = {
  109. vertical: scrollbar.vertical,
  110. horizontal: scrollbar.horizontal,
  111. verticalScrollbarSize: scrollbar.verticalScrollbarSize,
  112. horizontalScrollbarSize: scrollbar.horizontalScrollbarSize,
  113. scrollByPage: scrollbar.scrollByPage,
  114. handleMouseWheel: scrollbar.handleMouseWheel,
  115. mouseWheelScrollSensitivity: mouseWheelScrollSensitivity,
  116. fastScrollSensitivity: fastScrollSensitivity,
  117. scrollPredominantAxis: scrollPredominantAxis
  118. };
  119. this.scrollbar.updateOptions(newOpts);
  120. }
  121. if (e.hasChanged(133 /* EditorOption.layoutInfo */)) {
  122. this._setLayout();
  123. }
  124. return true;
  125. }
  126. onScrollChanged(e) {
  127. return true;
  128. }
  129. onThemeChanged(e) {
  130. this.scrollbar.updateClassName('editor-scrollable' + ' ' + getThemeTypeSelector(this._context.theme.type));
  131. return true;
  132. }
  133. // --- end event handlers
  134. prepareRender(ctx) {
  135. // Nothing to do
  136. }
  137. render(ctx) {
  138. this.scrollbar.renderNow();
  139. }
  140. }
  141. registerThemingParticipant((theme, collector) => {
  142. // Scrollbars
  143. const scrollbarShadowColor = theme.getColor(scrollbarShadow);
  144. if (scrollbarShadowColor) {
  145. collector.addRule(`
  146. .monaco-scrollable-element > .shadow.top {
  147. box-shadow: ${scrollbarShadowColor} 0 6px 6px -6px inset;
  148. }
  149. .monaco-scrollable-element > .shadow.left {
  150. box-shadow: ${scrollbarShadowColor} 6px 0 6px -6px inset;
  151. }
  152. .monaco-scrollable-element > .shadow.top.left {
  153. box-shadow: ${scrollbarShadowColor} 6px 6px 6px -6px inset;
  154. }
  155. `);
  156. }
  157. const scrollbarSliderBackgroundColor = theme.getColor(scrollbarSliderBackground);
  158. if (scrollbarSliderBackgroundColor) {
  159. collector.addRule(`
  160. .monaco-scrollable-element > .scrollbar > .slider {
  161. background: ${scrollbarSliderBackgroundColor};
  162. }
  163. `);
  164. }
  165. const scrollbarSliderHoverBackgroundColor = theme.getColor(scrollbarSliderHoverBackground);
  166. if (scrollbarSliderHoverBackgroundColor) {
  167. collector.addRule(`
  168. .monaco-scrollable-element > .scrollbar > .slider:hover {
  169. background: ${scrollbarSliderHoverBackgroundColor};
  170. }
  171. `);
  172. }
  173. const scrollbarSliderActiveBackgroundColor = theme.getColor(scrollbarSliderActiveBackground);
  174. if (scrollbarSliderActiveBackgroundColor) {
  175. collector.addRule(`
  176. .monaco-scrollable-element > .scrollbar > .slider.active {
  177. background: ${scrollbarSliderActiveBackgroundColor};
  178. }
  179. `);
  180. }
  181. });