diff --git a/src/vs/workbench/contrib/notebook/browser/media/notebook.css b/src/vs/workbench/contrib/notebook/browser/media/notebook.css index 0334bc126d324..b5d742ff80656 100644 --- a/src/vs/workbench/contrib/notebook/browser/media/notebook.css +++ b/src/vs/workbench/contrib/notebook/browser/media/notebook.css @@ -56,7 +56,8 @@ } .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell-drag-handle, -.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-drag-handle { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell-drag-handle, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .cell-drag-handle { visibility: visible; } @@ -152,11 +153,13 @@ .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .menu.mouseover, -.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .menu { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .menu, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .menu { visibility: visible; } -.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover { outline: none !important; } @@ -253,7 +256,8 @@ } .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell.runnable .run-button-container .monaco-toolbar, -.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell.runnable .run-button-container .monaco-toolbar { +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell.runnable .run-button-container .monaco-toolbar, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .cell.runnable .run-button-container .monaco-toolbar { visibility: visible; } @@ -270,6 +274,7 @@ } .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .cell .run-button-container .execution-count-label, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .cell .run-button-container .execution-count-label, .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .cell .run-button-container .execution-count-label { visibility: hidden; } @@ -283,6 +288,7 @@ } .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused .monaco-toolbar, +.monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-output-hover .monaco-toolbar, .monaco-workbench .part.editor > .content .notebook-editor > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover .monaco-toolbar { visibility: visible; } @@ -307,6 +313,7 @@ } .monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row:hover .notebook-cell-focus-indicator, +.monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row.cell-output-hover .notebook-cell-focus-indicator, .monaco-workbench .part.editor > .content .notebook-editor .monaco-list .monaco-list-row.focused .notebook-cell-focus-indicator { visibility: visible; } diff --git a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts index e03d061b8699c..16c7c0d32d07a 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookBrowser.ts @@ -463,6 +463,7 @@ export interface CellViewModelStateChangeEvent { languageChanged?: boolean; foldingStateChanged?: boolean; contentChanged?: boolean; + outputIsHoveredChanged?: boolean; } /** diff --git a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts index 6947fbbd0752d..7e64a1fafc9af 100644 --- a/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts +++ b/src/vs/workbench/contrib/notebook/browser/notebookEditor.ts @@ -1022,7 +1022,8 @@ registerThemingParticipant((theme, collector) => { collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container .seperator { background-color: ${cellToolbarSeperator} }`); collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .cell-bottom-toolbar-container .seperator-short { background-color: ${cellToolbarSeperator} }`); collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row > .monaco-toolbar { border: solid 1px ${cellToolbarSeperator}; }`); - collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .notebook-cell-focus-indicator { border-color: ${cellToolbarSeperator}; }`); + collector.addRule(`.monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row:hover .notebook-cell-focus-indicator, + .monaco-workbench .part.editor > .content .notebook-editor .monaco-list-row.cell-output-hover .notebook-cell-focus-indicator { border-color: ${cellToolbarSeperator}; }`); } const focusedCellIndicatorColor = theme.getColor(focusedCellIndicator); diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts index 08304b85c0d67..8f57a4a8c1a7b 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/backLayerWebView.ts @@ -20,13 +20,25 @@ import { IOpenerService } from 'vs/platform/opener/common/opener'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { isWeb } from 'vs/base/common/platform'; -export interface IDimentionMessage { +export interface IDimensionMessage { __vscode_notebook_message: boolean; type: 'dimension'; id: string; data: DOM.Dimension; } +export interface IMouseEnterMessage { + __vscode_notebook_message: boolean; + type: 'mouseenter'; + id: string; +} + +export interface IMouseLeaveMessage { + __vscode_notebook_message: boolean; + type: 'mouseleave'; + id: string; +} + export interface IWheelMessage { __vscode_notebook_message: boolean; type: 'did-scroll-wheel'; @@ -80,7 +92,7 @@ export interface IUpdatePreloadResourceMessage { resources: string[]; } -type IMessage = IDimentionMessage | IScrollAckMessage | IWheelMessage; +type IMessage = IDimensionMessage | IScrollAckMessage | IWheelMessage | IMouseEnterMessage | IMouseLeaveMessage; let version = 0; export class BackLayerWebView extends Disposable { @@ -279,6 +291,23 @@ ${loaderJs} newElement.id = id; document.getElementById('container').appendChild(newElement); cellOutputContainer = newElement; + + cellOutputContainer.addEventListener('mouseenter', () => { + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'mouseenter', + id: outputId, + data: { } + }); + }); + cellOutputContainer.addEventListener('mouseleave', () => { + vscode.postMessage({ + __vscode_notebook_message: true, + type: 'mouseleave', + id: outputId, + data: { } + }); + }); } let outputNode = document.createElement('div'); @@ -362,6 +391,15 @@ ${loaderJs} `; } + private resolveOutputId(id: string): { cell: CodeCellViewModel, output: IOutput } | undefined { + const output = this.reversedInsetMapping.get(id); + if (!output) { + return; + } + + return { cell: this.insetMapping.get(output)!.cell, output }; + } + initialize(content: string) { this.webview = this._createInset(this.webviewService, content); this.webview.mountTo(this.element); @@ -373,21 +411,28 @@ ${loaderJs} this._register(this.webview.onMessage((data: IMessage) => { if (data.__vscode_notebook_message) { if (data.type === 'dimension') { - let output = this.reversedInsetMapping.get(data.id); - - if (!output) { - return; - } - - let cell = this.insetMapping.get(output)!.cell; let height = data.data.height; let outputHeight = height; - if (cell) { + const info = this.resolveOutputId(data.id); + if (info) { + const { cell, output } = info; let outputIndex = cell.outputs.indexOf(output); cell.updateOutputHeight(outputIndex, outputHeight); this.notebookEditor.layoutNotebookCell(cell, cell.layoutInfo.totalHeight); } + } else if (data.type === 'mouseenter') { + const info = this.resolveOutputId(data.id); + if (info) { + const { cell } = info; + cell.outputIsHovered = true; + } + } else if (data.type === 'mouseleave') { + const info = this.resolveOutputId(data.id); + if (info) { + const { cell } = info; + cell.outputIsHovered = false; + } } else if (data.type === 'scroll-ack') { // const date = new Date(); // const top = data.data.top; diff --git a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts index 8d184694f8cfc..186ea1e8ad4ef 100644 --- a/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts +++ b/src/vs/workbench/contrib/notebook/browser/view/renderers/cellRenderer.ts @@ -722,6 +722,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende } } + private updateForHover(element: CodeCellViewModel, templateData: CodeCellRenderTemplate): void { + DOM.toggleClass(templateData.container, 'cell-output-hover', element.outputIsHovered); + } + renderElement(element: CodeCellViewModel, index: number, templateData: CodeCellRenderTemplate, height: number | undefined): void { this.commonRenderElement(element, index, templateData); @@ -762,6 +766,10 @@ export class CodeCellRenderer extends AbstractCellRenderer implements IListRende if (e.metadataChanged) { this.updateForMetadata(element, templateData, cellEditableKey); } + + if (e.outputIsHoveredChanged) { + this.updateForHover(element, templateData); + } })); this.setupCellToolbarActions(contextKeyService, templateData, elementDisposables); diff --git a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts index e408207cfcb42..270552b74efaa 100644 --- a/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts +++ b/src/vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel.ts @@ -49,6 +49,16 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod return this._editorHeight; } + private _hoveringOutput: boolean = false; + public get outputIsHovered(): boolean { + return this._hoveringOutput; + } + + public set outputIsHovered(v: boolean) { + this._hoveringOutput = v; + this._onDidChangeState.fire({ outputIsHoveredChanged: true }); + } + private _layoutInfo: CodeCellLayoutInfo; get layoutInfo() {