From be7c242f974b5f1ab9b3c2871ad517d73c969efc Mon Sep 17 00:00:00 2001 From: Beka Westberg Date: Fri, 15 Feb 2019 16:25:27 -0800 Subject: [PATCH] Fixed bubble positioning to work with simple toolboxes (PR #2279) Merge from BeksOmega/fixes/BubbleSimpleToolbox --- core/bubble.js | 146 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 107 insertions(+), 39 deletions(-) diff --git a/core/bubble.js b/core/bubble.js index 2605cbae5..305741b99 100644 --- a/core/bubble.js +++ b/core/bubble.js @@ -175,19 +175,20 @@ Blockly.Bubble.prototype.anchorXY_ = null; Blockly.Bubble.prototype.relativeLeft_ = 0; /** - * Relative Y coordinate of bubble with respect to the anchor's centre. + * Relative Y coordinate of bubble with respect to the anchor's centre, in + * workspace units. * @private */ Blockly.Bubble.prototype.relativeTop_ = 0; /** - * Width of bubble. + * Width of bubble, in workspace units. * @private */ Blockly.Bubble.prototype.width_ = 0; /** - * Height of bubble. + * Height of bubble, in workspace units. * @private */ Blockly.Bubble.prototype.height_ = 0; @@ -401,9 +402,15 @@ Blockly.Bubble.prototype.setAnchorLocation = function(xy) { * @private */ Blockly.Bubble.prototype.layoutBubble_ = function() { + // Get the metrics in workspace units. var metrics = this.workspace_.getMetrics(); - metrics.viewWidth /= this.workspace_.scale; metrics.viewLeft /= this.workspace_.scale; + metrics.viewWidth /= this.workspace_.scale; + metrics.viewTop /= this.workspace_.scale; + metrics.viewHeight /= this.workspace_.scale; + metrics.flyoutWidth /= this.workspace_.scale; + metrics.flyoutHeight /= this.workspace_.scale; + var optimalLeft = this.getOptimalRelativeLeft_(metrics); var optimalTop = this.getOptimalRelativeTop_(metrics); var bbox = this.shape_.getBBox(); @@ -441,6 +448,9 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { this.relativeTop_ = closerPosition.y; return; } + // TODO: I believe relativeLeft_ should actually be called relativeStart_ + // and then the math should be fixed to reflect this. (hopefully it'll + // make it look simpler) this.relativeLeft_ = fartherPosition.x; this.relativeTop_ = fartherPosition.y; }; @@ -458,27 +468,38 @@ Blockly.Bubble.prototype.layoutBubble_ = function() { * @private */ Blockly.Bubble.prototype.getOverlap_ = function(relativeMin, metrics) { - // The position of the top-start corner of the bubble in workspace units. + // The position of the top-left corner of the bubble in workspace units. var bubbleMin = { - x: relativeMin.x + (this.workspace_.RTL ? - metrics.viewWidth - this.anchorXY_.x : - this.anchorXY_.x), + x: this.workspace_.RTL ? (this.anchorXY_.x - relativeMin.x - this.width_) : + (relativeMin.x + this.anchorXY_.x), y: relativeMin.y + this.anchorXY_.y }; - // The position of the bottom-end corner of the bubble in workspace units. + // The position of the bottom-right corner of the bubble in workspace units. var bubbleMax = { x: bubbleMin.x + this.width_, y: bubbleMin.y + this.height_ }; - // The position of the top-start corner of the workspace. + + // We could adjust these values to account for the scrollbars, but the + // bubbles should have been adjusted to not collide with them anyway, so + // giving the workspace a slightly larger "bounding box" shouldn't affect the + // calculation. + + // The position of the top-left corner of the workspace. var workspaceMin = { - x: this.workspace_.RTL ? -metrics.viewLeft : metrics.viewLeft, - y: metrics.viewTop + x: metrics.viewLeft + ((metrics.toolboxPosition == Blockly.TOOLBOX_AT_LEFT) ? + metrics.flyoutWidth : 0), + y: metrics.viewTop + ((metrics.toolboxPosition == Blockly.TOOLBOX_AT_TOP) ? + metrics.flyoutHeight : 0) }; - // The position of the bottom-end corner of the workspace. + // The position of the bottom-right corner of the workspace. var workspaceMax = { - x: workspaceMin.x + metrics.viewWidth, - y: workspaceMin.y + metrics.viewHeight + x: metrics.viewLeft + metrics.viewWidth - + ((metrics.toolboxPosition == Blockly.TOOLBOX_AT_RIGHT) ? + metrics.flyoutWidth : 0), + y: metrics.viewTop + metrics.viewHeight - + ((metrics.toolboxPosition == Blockly.TOOLBOX_AT_BOTTOM) ? + metrics.flyoutHeight : 0) }; var overlapWidth = Math.min(bubbleMax.x, workspaceMax.x) - @@ -507,29 +528,56 @@ Blockly.Bubble.prototype.getOptimalRelativeLeft_ = function(metrics) { return relativeLeft; } - var anchorX = this.anchorXY_.x; if (this.workspace_.RTL) { - if (anchorX - metrics.viewLeft - relativeLeft - this.width_ < - Blockly.Scrollbar.scrollbarThickness) { + // Everything is flipped in RTL. + var bubbleRight = this.anchorXY_.x - relativeLeft; + var bubbleLeft = bubbleRight - this.width_; + var scrollbarRight = 0; + // Thickness in workspace units. + var scrollbarLeft = + Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale; + } else { + var bubbleLeft = relativeLeft + this.anchorXY_.x; + var bubbleRight = bubbleLeft + this.width_; + // Thickness in workspace units. + var scrollbarRight = + Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale; + var scrollbarLeft = 0; + } + + switch (metrics.toolboxPosition) { + case Blockly.TOOLBOX_AT_LEFT: + var workspaceLeft = metrics.viewLeft + metrics.flyoutWidth; + var workspaceRight = + metrics.viewLeft + metrics.viewWidth - scrollbarRight; + break; + case Blockly.TOOLBOX_AT_RIGHT: + var workspaceLeft = metrics.viewLeft + scrollbarLeft; + var workspaceRight = + metrics.viewLeft + metrics.viewWidth - metrics.flyoutWidth; + break; + default: + var workspaceLeft = metrics.viewLeft + scrollbarLeft; + var workspaceRight = + metrics.viewLeft + metrics.viewWidth - scrollbarRight; + break; + } + + if (this.workspace_.RTL) { + if (bubbleLeft < workspaceLeft) { // Slide the bubble right until it is onscreen. - relativeLeft = anchorX - metrics.viewLeft - this.width_ - - Blockly.Scrollbar.scrollbarThickness; - } else if (anchorX - metrics.viewLeft - relativeLeft > - metrics.viewWidth) { + relativeLeft = -(workspaceLeft - this.anchorXY_.x + this.width_); + } else if (bubbleRight > workspaceRight) { // Slide the bubble left until it is onscreen. - relativeLeft = anchorX - metrics.viewLeft - metrics.viewWidth; + relativeLeft = -(workspaceRight - this.anchorXY_.x); } } else { - if (anchorX + relativeLeft < metrics.viewLeft) { + if (bubbleLeft < workspaceLeft) { // Slide the bubble right until it is onscreen. - relativeLeft = metrics.viewLeft - anchorX; - } else if (metrics.viewLeft + metrics.viewWidth < - anchorX + relativeLeft + this.width_ + - Blockly.BlockSvg.SEP_SPACE_X + - Blockly.Scrollbar.scrollbarThickness) { + relativeLeft = workspaceLeft - this.anchorXY_.x; + } else if (bubbleRight > workspaceRight) { // Slide the bubble left until it is onscreen. - relativeLeft = metrics.viewLeft + metrics.viewWidth - anchorX - - this.width_ - Blockly.Scrollbar.scrollbarThickness; + relativeLeft = workspaceRight - this.anchorXY_.x - this.width_; } } @@ -554,17 +602,37 @@ Blockly.Bubble.prototype.getOptimalRelativeTop_ = function(metrics) { return relativeTop; } + var bubbleTop = this.anchorXY_.y + relativeTop; + var bubbleBottom = bubbleTop + this.height_; + + // Thickness in workspace units. + var scrollbarThickness = + Blockly.Scrollbar.scrollbarThickness / this.workspace_.scale; + switch (metrics.toolboxPosition) { + case Blockly.TOOLBOX_AT_TOP: + var workspaceTop = metrics.viewTop + metrics.flyoutHeight; + var workspaceBottom = metrics.viewTop + metrics.viewHeight - + scrollbarThickness; + break; + case Blockly.TOOLBOX_AT_BOTTOM: + var workspaceTop = metrics.viewTop; + var workspaceBottom = metrics.viewTop + metrics.viewHeight + - metrics.flyoutHeight; + break; + default: + var workspaceTop = metrics.viewTop; + var workspaceBottom = metrics.viewTop + metrics.viewHeight - + scrollbarThickness; + break; + } + var anchorY = this.anchorXY_.y; - if (anchorY + relativeTop < metrics.viewTop) { + if (bubbleTop < workspaceTop) { // Slide the bubble down until it is onscreen. - relativeTop = metrics.viewTop - anchorY; - } else if (metrics.viewTop + metrics.viewHeight < - anchorY + relativeTop + this.height_ + - Blockly.BlockSvg.SEP_SPACE_Y + - Blockly.Scrollbar.scrollbarThickness) { + relativeTop = workspaceTop - anchorY; + } else if (bubbleBottom > workspaceBottom) { // Slide the bubble up until it is onscreen. - relativeTop = metrics.viewTop + metrics.viewHeight - anchorY - - this.height_ - Blockly.Scrollbar.scrollbarThickness; + relativeTop = workspaceBottom - anchorY - this.height_; } return relativeTop;