Path: blob/main/src/vs/editor/contrib/hover/browser/resizableContentWidget.ts
4779 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { ResizableHTMLElement } from '../../../../base/browser/ui/resizable/resizable.js';6import { Disposable } from '../../../../base/common/lifecycle.js';7import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from '../../../browser/editorBrowser.js';8import { EditorOption } from '../../../common/config/editorOptions.js';9import { IPosition, Position } from '../../../common/core/position.js';10import * as dom from '../../../../base/browser/dom.js';1112const TOP_HEIGHT = 30;13const BOTTOM_HEIGHT = 24;1415export abstract class ResizableContentWidget extends Disposable implements IContentWidget {1617readonly allowEditorOverflow: boolean = true;18readonly suppressMouseDown: boolean = false;1920protected readonly _resizableNode = this._register(new ResizableHTMLElement());21protected _contentPosition: IContentWidgetPosition | null = null;2223private _isResizing: boolean = false;2425constructor(26protected readonly _editor: ICodeEditor,27minimumSize: dom.IDimension = new dom.Dimension(10, 10)28) {29super();30this._resizableNode.domNode.style.position = 'absolute';31this._resizableNode.minSize = dom.Dimension.lift(minimumSize);32this._resizableNode.layout(minimumSize.height, minimumSize.width);33this._resizableNode.enableSashes(true, true, true, true);34this._register(this._resizableNode.onDidResize(e => {35this._resize(new dom.Dimension(e.dimension.width, e.dimension.height));36if (e.done) {37this._isResizing = false;38}39}));40this._register(this._resizableNode.onDidWillResize(() => {41this._isResizing = true;42}));43}4445get isResizing() {46return this._isResizing;47}4849abstract getId(): string;5051getDomNode(): HTMLElement {52return this._resizableNode.domNode;53}5455getPosition(): IContentWidgetPosition | null {56return this._contentPosition;57}5859get position(): Position | undefined {60return this._contentPosition?.position ? Position.lift(this._contentPosition.position) : undefined;61}6263protected _availableVerticalSpaceAbove(position: IPosition): number | undefined {64const editorDomNode = this._editor.getDomNode();65const mouseBox = this._editor.getScrolledVisiblePosition(position);66if (!editorDomNode || !mouseBox) {67return;68}69const editorBox = dom.getDomNodePagePosition(editorDomNode);70return editorBox.top + mouseBox.top - TOP_HEIGHT;71}7273protected _availableVerticalSpaceBelow(position: IPosition): number | undefined {74const editorDomNode = this._editor.getDomNode();75const mouseBox = this._editor.getScrolledVisiblePosition(position);76if (!editorDomNode || !mouseBox) {77return;78}79const editorBox = dom.getDomNodePagePosition(editorDomNode);80const bodyBox = dom.getClientArea(editorDomNode.ownerDocument.body);81const mouseBottom = editorBox.top + mouseBox.top + mouseBox.height;82return bodyBox.height - mouseBottom - BOTTOM_HEIGHT;83}8485protected _findPositionPreference(widgetHeight: number, showAtPosition: IPosition): ContentWidgetPositionPreference | undefined {86const maxHeightBelow = Math.min(this._availableVerticalSpaceBelow(showAtPosition) ?? Infinity, widgetHeight);87const maxHeightAbove = Math.min(this._availableVerticalSpaceAbove(showAtPosition) ?? Infinity, widgetHeight);88const maxHeight = Math.min(Math.max(maxHeightAbove, maxHeightBelow), widgetHeight);89const height = Math.min(widgetHeight, maxHeight);90let renderingAbove: ContentWidgetPositionPreference;91if (this._editor.getOption(EditorOption.hover).above) {92renderingAbove = height <= maxHeightAbove ? ContentWidgetPositionPreference.ABOVE : ContentWidgetPositionPreference.BELOW;93} else {94renderingAbove = height <= maxHeightBelow ? ContentWidgetPositionPreference.BELOW : ContentWidgetPositionPreference.ABOVE;95}96if (renderingAbove === ContentWidgetPositionPreference.ABOVE) {97this._resizableNode.enableSashes(true, true, false, false);98} else {99this._resizableNode.enableSashes(false, true, true, false);100}101return renderingAbove;102}103104protected _resize(dimension: dom.Dimension): void {105this._resizableNode.layout(dimension.height, dimension.width);106}107}108109110