From faadee87a554aa8fbf8a82a601576ca097b7a0aa Mon Sep 17 00:00:00 2001 From: Christopher Leidigh Date: Fri, 17 Aug 2018 13:10:45 -0400 Subject: [PATCH] SelectBox: Prevent layout/hide on no room/offscreen Fixes: #55750 (#56173) --- .../browser/ui/contextview/contextview.ts | 5 ++ .../browser/ui/selectBox/selectBoxCustom.ts | 82 ++++++++++++++----- 2 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 8da408322a4..c16fc27af11 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -173,6 +173,11 @@ export class ContextView { } private doLayout(): void { + // Check that we still have a delegate - this.delegate.layout may have hidden + if (!this.isVisible()) { + return; + } + // Get anchor let anchor = this.delegate.getAnchor(); diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index d78f3f89e15..7a4b27ed1cf 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -82,7 +82,7 @@ class SelectListRenderer implements IRenderer { private static readonly DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN = 32; - private static readonly DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN = 42; + private static readonly DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN = 2; private static readonly DEFAULT_MINIMUM_VISIBLE_OPTIONS = 3; private _isVisible: boolean; @@ -393,9 +393,11 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate (window.innerHeight - 22) + || selectPosition.top < SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN + || ((maxVisibleOptionsBelow < 1) && (maxVisibleOptionsAbove < 1))) { + // Indicate we cannot open + return false; + } + + // Determine if we have to flip up // Always show complete list items - never more than Max available vertical height - if (listHeight + verticalPadding > maxSelectDropDownHeight) { - const maxVisibleOptions = ((Math.floor((maxSelectDropDownHeight - verticalPadding) / this.getHeight()))); - - // Check if we can at least show min items otherwise flip above - if (maxVisibleOptions < SelectBoxList.DEFAULT_MINIMUM_VISIBLE_OPTIONS) { - this._dropDownPosition = AnchorPosition.ABOVE; - } else { - this._dropDownPosition = AnchorPosition.BELOW; - } + if (maxVisibleOptionsBelow < SelectBoxList.DEFAULT_MINIMUM_VISIBLE_OPTIONS + && maxVisibleOptionsAbove > maxVisibleOptionsBelow + && this.options.length > maxVisibleOptionsBelow + ) { + this._dropDownPosition = AnchorPosition.ABOVE; + } else { + this._dropDownPosition = AnchorPosition.BELOW; } // Do full layout on showSelectDropDown only - return; + return true; + } + + // Check if select out of viewport or cutting into status bar + if ((selectPosition.top + selectPosition.height) > (window.innerHeight - 22) + || selectPosition.top < SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN + || (this._dropDownPosition === AnchorPosition.BELOW && maxVisibleOptionsBelow < 1) + || (this._dropDownPosition === AnchorPosition.ABOVE && maxVisibleOptionsAbove < 1)) { + // Cannot properly layout, close and hide + this.hideSelectDropDown(true); + return false; } // Make visible to enable measurements @@ -486,15 +514,22 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate maxSelectDropDownHeight) { - listHeight = ((Math.floor((maxSelectDropDownHeight - verticalPadding) / this.getHeight())) * this.getHeight()); + if (minRequiredDropDownHeight > maxSelectDropDownHeightBelow) { + listHeight = (maxVisibleOptionsBelow * this.getHeight() + verticalPadding); } } else { // Set container height to max from select top to margin (default/minTopMargin) - maxSelectDropDownHeight = (selectPosition.top - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN); - if (listHeight + verticalPadding > maxSelectDropDownHeight) { - listHeight = ((Math.floor((maxSelectDropDownHeight - SelectBoxList.DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN) / this.getHeight())) * this.getHeight()); + if (minRequiredDropDownHeight > maxSelectDropDownHeightAbove) { + // listHeight = ((Math.floor((maxSelectDropDownHeightBelow - verticalPadding) / this.getHeight())) * this.getHeight()); + listHeight = (maxVisibleOptionsAbove * this.getHeight() + verticalPadding); } } @@ -522,6 +557,9 @@ export class SelectBoxList implements ISelectBoxDelegate, IVirtualDelegate