findOptionsWidget.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  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 { CaseSensitiveCheckbox, RegexCheckbox, WholeWordsCheckbox } from '../../../base/browser/ui/findinput/findInputCheckboxes.js';
  7. import { Widget } from '../../../base/browser/ui/widget.js';
  8. import { RunOnceScheduler } from '../../../base/common/async.js';
  9. import { FIND_IDS } from './findModel.js';
  10. import { contrastBorder, editorWidgetBackground, editorWidgetForeground, inputActiveOptionBackground, inputActiveOptionBorder, inputActiveOptionForeground, widgetShadow } from '../../../platform/theme/common/colorRegistry.js';
  11. import { registerThemingParticipant } from '../../../platform/theme/common/themeService.js';
  12. export class FindOptionsWidget extends Widget {
  13. constructor(editor, state, keybindingService, themeService) {
  14. super();
  15. this._hideSoon = this._register(new RunOnceScheduler(() => this._hide(), 2000));
  16. this._isVisible = false;
  17. this._editor = editor;
  18. this._state = state;
  19. this._keybindingService = keybindingService;
  20. this._domNode = document.createElement('div');
  21. this._domNode.className = 'findOptionsWidget';
  22. this._domNode.style.display = 'none';
  23. this._domNode.style.top = '10px';
  24. this._domNode.setAttribute('role', 'presentation');
  25. this._domNode.setAttribute('aria-hidden', 'true');
  26. const inputActiveOptionBorderColor = themeService.getColorTheme().getColor(inputActiveOptionBorder);
  27. const inputActiveOptionForegroundColor = themeService.getColorTheme().getColor(inputActiveOptionForeground);
  28. const inputActiveOptionBackgroundColor = themeService.getColorTheme().getColor(inputActiveOptionBackground);
  29. this.caseSensitive = this._register(new CaseSensitiveCheckbox({
  30. appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleCaseSensitiveCommand),
  31. isChecked: this._state.matchCase,
  32. inputActiveOptionBorder: inputActiveOptionBorderColor,
  33. inputActiveOptionForeground: inputActiveOptionForegroundColor,
  34. inputActiveOptionBackground: inputActiveOptionBackgroundColor
  35. }));
  36. this._domNode.appendChild(this.caseSensitive.domNode);
  37. this._register(this.caseSensitive.onChange(() => {
  38. this._state.change({
  39. matchCase: this.caseSensitive.checked
  40. }, false);
  41. }));
  42. this.wholeWords = this._register(new WholeWordsCheckbox({
  43. appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleWholeWordCommand),
  44. isChecked: this._state.wholeWord,
  45. inputActiveOptionBorder: inputActiveOptionBorderColor,
  46. inputActiveOptionForeground: inputActiveOptionForegroundColor,
  47. inputActiveOptionBackground: inputActiveOptionBackgroundColor
  48. }));
  49. this._domNode.appendChild(this.wholeWords.domNode);
  50. this._register(this.wholeWords.onChange(() => {
  51. this._state.change({
  52. wholeWord: this.wholeWords.checked
  53. }, false);
  54. }));
  55. this.regex = this._register(new RegexCheckbox({
  56. appendTitle: this._keybindingLabelFor(FIND_IDS.ToggleRegexCommand),
  57. isChecked: this._state.isRegex,
  58. inputActiveOptionBorder: inputActiveOptionBorderColor,
  59. inputActiveOptionForeground: inputActiveOptionForegroundColor,
  60. inputActiveOptionBackground: inputActiveOptionBackgroundColor
  61. }));
  62. this._domNode.appendChild(this.regex.domNode);
  63. this._register(this.regex.onChange(() => {
  64. this._state.change({
  65. isRegex: this.regex.checked
  66. }, false);
  67. }));
  68. this._editor.addOverlayWidget(this);
  69. this._register(this._state.onFindReplaceStateChange((e) => {
  70. let somethingChanged = false;
  71. if (e.isRegex) {
  72. this.regex.checked = this._state.isRegex;
  73. somethingChanged = true;
  74. }
  75. if (e.wholeWord) {
  76. this.wholeWords.checked = this._state.wholeWord;
  77. somethingChanged = true;
  78. }
  79. if (e.matchCase) {
  80. this.caseSensitive.checked = this._state.matchCase;
  81. somethingChanged = true;
  82. }
  83. if (!this._state.isRevealed && somethingChanged) {
  84. this._revealTemporarily();
  85. }
  86. }));
  87. this._register(dom.addDisposableNonBubblingMouseOutListener(this._domNode, (e) => this._onMouseOut()));
  88. this._register(dom.addDisposableListener(this._domNode, 'mouseover', (e) => this._onMouseOver()));
  89. this._applyTheme(themeService.getColorTheme());
  90. this._register(themeService.onDidColorThemeChange(this._applyTheme.bind(this)));
  91. }
  92. _keybindingLabelFor(actionId) {
  93. let kb = this._keybindingService.lookupKeybinding(actionId);
  94. if (!kb) {
  95. return '';
  96. }
  97. return ` (${kb.getLabel()})`;
  98. }
  99. dispose() {
  100. this._editor.removeOverlayWidget(this);
  101. super.dispose();
  102. }
  103. // ----- IOverlayWidget API
  104. getId() {
  105. return FindOptionsWidget.ID;
  106. }
  107. getDomNode() {
  108. return this._domNode;
  109. }
  110. getPosition() {
  111. return {
  112. preference: 0 /* TOP_RIGHT_CORNER */
  113. };
  114. }
  115. highlightFindOptions() {
  116. this._revealTemporarily();
  117. }
  118. _revealTemporarily() {
  119. this._show();
  120. this._hideSoon.schedule();
  121. }
  122. _onMouseOut() {
  123. this._hideSoon.schedule();
  124. }
  125. _onMouseOver() {
  126. this._hideSoon.cancel();
  127. }
  128. _show() {
  129. if (this._isVisible) {
  130. return;
  131. }
  132. this._isVisible = true;
  133. this._domNode.style.display = 'block';
  134. }
  135. _hide() {
  136. if (!this._isVisible) {
  137. return;
  138. }
  139. this._isVisible = false;
  140. this._domNode.style.display = 'none';
  141. }
  142. _applyTheme(theme) {
  143. let inputStyles = {
  144. inputActiveOptionBorder: theme.getColor(inputActiveOptionBorder),
  145. inputActiveOptionForeground: theme.getColor(inputActiveOptionForeground),
  146. inputActiveOptionBackground: theme.getColor(inputActiveOptionBackground)
  147. };
  148. this.caseSensitive.style(inputStyles);
  149. this.wholeWords.style(inputStyles);
  150. this.regex.style(inputStyles);
  151. }
  152. }
  153. FindOptionsWidget.ID = 'editor.contrib.findOptionsWidget';
  154. registerThemingParticipant((theme, collector) => {
  155. const widgetBackground = theme.getColor(editorWidgetBackground);
  156. if (widgetBackground) {
  157. collector.addRule(`.monaco-editor .findOptionsWidget { background-color: ${widgetBackground}; }`);
  158. }
  159. const widgetForeground = theme.getColor(editorWidgetForeground);
  160. if (widgetForeground) {
  161. collector.addRule(`.monaco-editor .findOptionsWidget { color: ${widgetForeground}; }`);
  162. }
  163. const widgetShadowColor = theme.getColor(widgetShadow);
  164. if (widgetShadowColor) {
  165. collector.addRule(`.monaco-editor .findOptionsWidget { box-shadow: 0 0 8px 2px ${widgetShadowColor}; }`);
  166. }
  167. const hcBorder = theme.getColor(contrastBorder);
  168. if (hcBorder) {
  169. collector.addRule(`.monaco-editor .findOptionsWidget { border: 2px solid ${hcBorder}; }`);
  170. }
  171. });