Make cell run button sticky while scrolling. Fix #142803

This commit is contained in:
Rob Lourens 2022-02-10 20:10:24 -08:00
parent 59e217e6be
commit 947a99acad
6 changed files with 60 additions and 9 deletions

View file

@ -192,6 +192,7 @@
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .cell {
display: flex;
position: relative;
}
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:not(.selected) .monaco-editor .lines-content .selected-text,
@ -570,6 +571,8 @@
position: absolute;
flex-shrink: 0;
z-index: var(--z-index-run-button-container);
width: 35px;
left: -35px;
}
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .run-button-container .monaco-toolbar {
@ -599,6 +602,8 @@
white-space: pre;
box-sizing: border-box;
opacity: .7;
width: 35px;
left: -35px;
/* Sizing hacks */
bottom: 0px;

View file

@ -135,6 +135,7 @@ export interface CodeCellLayoutInfo {
readonly fontInfo: FontInfo | null;
readonly editorHeight: number;
readonly editorWidth: number;
readonly statusBarHeight: number;
readonly totalHeight: number;
readonly outputContainerOffset: number;
readonly outputTotalHeight: number;
@ -160,6 +161,7 @@ export interface MarkdownCellLayoutInfo {
readonly fontInfo: FontInfo | null;
readonly editorWidth: number;
readonly editorHeight: number;
readonly statusBarHeight: number;
readonly previewHeight: number;
readonly bottomToolbarOffset: number;
readonly totalHeight: number;
@ -189,7 +191,7 @@ export interface ICellViewModel extends IGenericCellViewModel {
readonly model: NotebookCellTextModel;
readonly id: string;
readonly textBuffer: IReadonlyTextBuffer;
readonly layoutInfo: { totalHeight: number; bottomToolbarOffset: number; editorWidth: number };
readonly layoutInfo: { totalHeight: number; bottomToolbarOffset: number; editorWidth: number; editorHeight: number; statusBarHeight: number };
readonly onDidChangeLayout: Event<ICommonCellViewModelLayoutChangeInfo>;
readonly onDidChangeCellStatusBarItems: Event<void>;
readonly onCellDecorationsChanged: Event<{ added: INotebookCellDecorationOptions[]; removed: INotebookCellDecorationOptions[] }>;
@ -384,6 +386,7 @@ export interface INotebookEditor {
readonly notebookOptions: NotebookOptions;
readonly isDisposed: boolean;
readonly activeKernel: INotebookKernel | undefined;
readonly scrollTop: number;
//#endregion
getLength(): number;
@ -600,6 +603,8 @@ export interface INotebookEditor {
findStop(): void;
showProgress(): void;
hideProgress(): void;
getAbsoluteTopOfElement(cell: ICellViewModel): number;
}
export interface IActiveNotebookEditor extends INotebookEditor {

View file

@ -853,8 +853,6 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
// show more container
styleSheets.push(`.notebookOverlay .output-show-more-container { margin: 0px ${cellRightMargin}px 0px ${codeCellLeftMargin + cellRunGutter}px; }`);
styleSheets.push(`.notebookOverlay .output-show-more-container { width: calc(100% - ${codeCellLeftMargin + cellRunGutter + cellRightMargin}px); }`);
styleSheets.push(`.notebookOverlay .cell .run-button-container { width: 35px; left: ${codeCellLeftMargin + cellRunGutter - 35}px }`);
styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row .execution-count-label { left: ${codeCellLeftMargin}px; width: ${cellRunGutter}px; }`);
styleSheets.push(`.notebookOverlay .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row div.cell.markdown { padding-left: ${cellRunGutter}px; }`);
styleSheets.push(`.monaco-workbench .notebookOverlay > .cell-list-container .notebook-folding-indicator { left: ${(markdownCellGutter - 20) / 2 + markdownCellLeftMargin}px; }`);
@ -1931,6 +1929,14 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditorD
});
}
get scrollTop() {
return this._list.scrollTop;
}
getAbsoluteTopOfElement(cell: ICellViewModel) {
return this._list.getAbsoluteTopOfElement(cell);
}
isScrolledToBottom() {
return this._listViewInfoAccessor.isScrolledToBottom();
}

View file

@ -7,6 +7,7 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { Action, IAction } from 'vs/base/common/actions';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { MarshalledId } from 'vs/base/common/marshalling';
import { clamp } from 'vs/base/common/numbers';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { localize } from 'vs/nls';
import { DropdownWithPrimaryActionViewItem } from 'vs/platform/actions/browser/dropdownWithPrimaryActionViewItem';
@ -25,7 +26,9 @@ import { BaseCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/vi
import { NOTEBOOK_CELL_EXECUTION_STATE, NOTEBOOK_CELL_LIST_FOCUSED, NOTEBOOK_CELL_TYPE, NOTEBOOK_EDITOR_FOCUSED } from 'vs/workbench/contrib/notebook/common/notebookContextKeys';
export class RunToolbar extends CellPart {
toolbar!: ToolBar;
private toolbar!: ToolBar;
private currentElement: ICellViewModel | undefined;
constructor(
readonly notebookEditor: INotebookEditorDelegate,
@ -39,6 +42,8 @@ export class RunToolbar extends CellPart {
) {
super();
this.notebookEditor.onDidScroll(() => this.updateForScroll());
const menu = this._register(menuService.createMenu(this.notebookEditor.creationOptions.menuIds.cellExecutePrimary!, contextKeyService));
this.createRunCellToolbar(runButtonContainer, cellContainer, contextKeyService);
const updateActions = () => {
@ -51,7 +56,27 @@ export class RunToolbar extends CellPart {
this._register(this.notebookEditor.notebookOptions.onDidChangeOptions(updateActions));
}
private updateForScroll() {
if (this.currentElement) {
if (this.currentElement.isInputCollapsed) {
this.runButtonContainer.style.top = '';
} else {
const scrollTop = this.notebookEditor.scrollTop;
const elementTop = this.notebookEditor.getAbsoluteTopOfElement(this.currentElement);
const scrollPadding = this.notebookEditor.notebookOptions.computeTopInsertToolbarHeight(this.notebookEditor.textModel?.viewType);
const diff = scrollTop - scrollPadding - elementTop;
const maxTop = this.currentElement.layoutInfo.editorHeight + this.currentElement.layoutInfo.statusBarHeight - 45; // subtract roughly the height of the execution order label plus padding
const top = maxTop > 20 ? // Don't move the run button if it can only move a very short distance
clamp(0, diff, maxTop) :
0;
this.runButtonContainer.style.top = `${top}px`;
}
}
}
renderCell(element: ICellViewModel, templateData: BaseCellRenderTemplate): void {
this.currentElement = element;
this.updateForScroll();
this.toolbar.context = <INotebookCellActionContext>{
ui: true,
cell: element,

View file

@ -133,6 +133,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
editorWidth: initialNotebookLayoutInfo
? this.viewContext.notebookOptions.computeCodeCellEditorWidth(initialNotebookLayoutInfo.width)
: 0,
statusBarHeight: 0,
outputContainerOffset: 0,
outputTotalHeight: 0,
outputShowMoreContainerHeight: 0,
@ -188,13 +189,13 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
newState = CellLayoutState.Estimated;
}
const statusbarHeight = this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata, this.uri);
const codeIndicatorHeight = editorHeight + statusbarHeight;
const statusBarHeight = this.viewContext.notebookOptions.computeEditorStatusbarHeight(this.internalMetadata, this.uri);
const codeIndicatorHeight = editorHeight + statusBarHeight;
const outputIndicatorHeight = outputTotalHeight + outputShowMoreContainerHeight;
const outputContainerOffset = notebookLayoutConfiguration.editorToolbarHeight
+ notebookLayoutConfiguration.cellTopMargin // CELL_TOP_MARGIN
+ editorHeight
+ statusbarHeight;
+ statusBarHeight;
const outputShowMoreContainerOffset = totalHeight
- bottomToolbarDimensions.bottomToolbarGap
- bottomToolbarDimensions.bottomToolbarHeight / 2
@ -208,6 +209,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
fontInfo: state.font ?? this._layoutInfo.fontInfo ?? null,
editorHeight,
editorWidth,
statusBarHeight,
outputContainerOffset,
outputTotalHeight,
outputShowMoreContainerHeight,
@ -242,6 +244,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
fontInfo: state.font ?? this._layoutInfo.fontInfo ?? null,
editorHeight: this._layoutInfo.editorHeight,
editorWidth,
statusBarHeight: 0,
outputContainerOffset,
outputTotalHeight,
outputShowMoreContainerHeight,
@ -271,6 +274,7 @@ export class CodeCellViewModel extends BaseCellViewModel implements ICellViewMod
fontInfo: this._layoutInfo.fontInfo,
editorHeight: this._layoutInfo.editorHeight,
editorWidth: this._layoutInfo.editorWidth,
statusBarHeight: this.layoutInfo.statusBarHeight,
outputContainerOffset: this._layoutInfo.outputContainerOffset,
outputTotalHeight: this._layoutInfo.outputTotalHeight,
outputShowMoreContainerHeight: this._layoutInfo.outputShowMoreContainerHeight,

View file

@ -45,8 +45,10 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
}
private _editorHeight = 0;
private _statusBarHeight = 0;
set editorHeight(newHeight: number) {
this._editorHeight = newHeight;
this._statusBarHeight = this.viewContext.notebookOptions.computeStatusBarHeight();
this._updateTotalHeight(this._computeTotalHeight());
}
@ -115,7 +117,8 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
bottomToolbarOffset: bottomToolbarGap,
totalHeight: 100,
layoutState: CellLayoutState.Uninitialized,
foldHintHeight: 0
foldHintHeight: 0,
statusBarHeight: 0
};
this._register(this.onDidChangeState(e => {
@ -137,7 +140,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
+ layoutConfiguration.markdownCellTopMargin
+ layoutConfiguration.markdownCellBottomMargin
+ bottomToolbarGap
+ this.viewContext.notebookOptions.computeStatusBarHeight();
+ this._statusBarHeight;
} else {
// @rebornix
// On file open, the previewHeight + bottomToolbarGap for a cell out of viewport can be 0
@ -197,6 +200,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
editorWidth,
previewHeight,
editorHeight: this._editorHeight,
statusBarHeight: this._statusBarHeight,
bottomToolbarOffset: this.viewContext.notebookOptions.computeBottomToolbarOffset(totalHeight, this.viewType),
totalHeight,
layoutState: CellLayoutState.Measured,
@ -214,6 +218,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
fontInfo: state.font || this._layoutInfo.fontInfo,
editorWidth,
editorHeight: this._editorHeight,
statusBarHeight: this._statusBarHeight,
previewHeight: this._previewHeight,
bottomToolbarOffset: this.viewContext.notebookOptions.computeBottomToolbarOffset(totalHeight, this.viewType),
totalHeight,
@ -236,6 +241,7 @@ export class MarkupCellViewModel extends BaseCellViewModel implements ICellViewM
bottomToolbarOffset: this._layoutInfo.bottomToolbarOffset,
totalHeight: totalHeight,
editorHeight: this._editorHeight,
statusBarHeight: this._statusBarHeight,
layoutState: CellLayoutState.FromCache,
foldHintHeight: this._layoutInfo.foldHintHeight
};