From 62547d8843736c73b3f10195ea9d852976e78adc Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Sun, 5 Apr 2026 17:30:37 +0100 Subject: [PATCH 1/3] Use custom Blockly metrics manager for overlay flyout behavior --- main/blocklyinit.js | 92 ++++++++++++++++++++++++--------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/main/blocklyinit.js b/main/blocklyinit.js index ec57ec37..7d318bba 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -606,6 +606,55 @@ export function initializeWorkspace() { } export function createBlocklyWorkspace() { + class OverlayMetricsManager extends Blockly.MetricsManager { + getAbsoluteMetrics() { + const absolute = super.getAbsoluteMetrics(); + const flyout = this.workspace_.getFlyout?.(); + if (!flyout || flyout.autoClose) return absolute; + + const flyoutMetrics = this.getFlyoutMetrics(); + const toolboxPosition = this.getToolboxMetrics().position; + const Position = Blockly.utils.toolbox.Position; + + const adjusted = { ...absolute }; + if (toolboxPosition === Position.LEFT) { + adjusted.left = Math.max(0, adjusted.left - flyoutMetrics.width); + } else if (toolboxPosition === Position.TOP) { + adjusted.top = Math.max(0, adjusted.top - flyoutMetrics.height); + } + + return adjusted; + } + + getViewMetrics(opt_getWorkspaceCoordinates) { + const view = super.getViewMetrics(opt_getWorkspaceCoordinates); + const flyout = this.workspace_.getFlyout?.(); + if (!flyout || flyout.autoClose) return view; + + const flyoutMetrics = this.getFlyoutMetrics(); + const toolboxPosition = this.getToolboxMetrics().position; + const Position = Blockly.utils.toolbox.Position; + const scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1; + const flyoutWidth = flyoutMetrics.width / scale; + const flyoutHeight = flyoutMetrics.height / scale; + const adjusted = { ...view }; + + if (toolboxPosition === Position.LEFT) { + adjusted.left -= flyoutWidth; + adjusted.width += flyoutWidth; + } else if (toolboxPosition === Position.RIGHT) { + adjusted.width += flyoutWidth; + } else if (toolboxPosition === Position.TOP) { + adjusted.top -= flyoutHeight; + adjusted.height += flyoutHeight; + } else if (toolboxPosition === Position.BOTTOM) { + adjusted.height += flyoutHeight; + } + + return adjusted; + } + } + // Register the custom renderer Blockly.registry.register( Blockly.registry.Type.RENDERER, @@ -636,6 +685,7 @@ export function createBlocklyWorkspace() { ); workspace = Blockly.inject("blocklyDiv", options); + workspace.setMetricsManager(new OverlayMetricsManager(workspace)); // Initialize keyboard navigation. @@ -951,48 +1001,6 @@ export function createBlocklyWorkspace() { shortcutRegistry.register(wrappedShortcut, true); })(); - // Keep scrolling; remove only the obvious flyout-width bump. - (function simpleNoBumpTranslate() { - const ws = Blockly.getMainWorkspace(); - const original = ws.translate.bind(ws); - - ws.translate = function (requestedX, newY) { - const tb = this.getToolbox?.(); - const fo = this.getFlyout?.(); - const mm = this.getMetricsManager?.(); - - // Toolbox edge on the left. Prefer toolbox.getWidth(); fallback to absolute metrics. - const tbW = - (tb && tb.getWidth?.()) ?? - (mm && mm.getAbsoluteMetrics ? mm.getAbsoluteMetrics().left : 0) ?? - 0; - - let x = requestedX; - - // Only adjust when the flyout is actually visible. - if (fo && fo.isVisible?.()) { - const foW = fo.getWidth?.() || 0; - const EPS = 1; // small float tolerance - - if (foW > 0) { - // Case 1: absolute shove to ≈ toolbox + flyout - if (x >= tbW + foW - EPS) { - x -= foW; - } - // Case 2: relative shove by ≈ flyout from current position - else if (x - this.scrollX >= foW - EPS) { - x -= foW; - } - } - } - - // Never allow the origin to go left of the toolbox edge. - if (x < tbW) x = tbW; - - return original(x, newY); - }; - })(); - // ------- Pointer tracking for "paste at pointer" ------- const mainWs = Blockly.getMainWorkspace(); let lastCM = { x: 0, y: 0 }; From cb7a8e4dfbccea29b2c444f8b122898187a586c6 Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Sun, 5 Apr 2026 17:48:30 +0100 Subject: [PATCH 2/3] Stabilize toolbox metrics to prevent category-specific workspace shifts --- main/blocklyinit.js | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 7d318bba..9b23fdf6 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -607,6 +607,44 @@ export function initializeWorkspace() { export function createBlocklyWorkspace() { class OverlayMetricsManager extends Blockly.MetricsManager { + constructor(workspaceRef) { + super(workspaceRef); + this.stableToolboxWidth_ = 0; + this.stableToolboxHeight_ = 0; + } + + getToolboxMetrics() { + const toolboxMetrics = super.getToolboxMetrics(); + const Position = Blockly.utils.toolbox.Position; + const isVertical = + toolboxMetrics.position === Position.LEFT || + toolboxMetrics.position === Position.RIGHT; + const isHorizontal = + toolboxMetrics.position === Position.TOP || + toolboxMetrics.position === Position.BOTTOM; + + if (isVertical && toolboxMetrics.width > 0) { + this.stableToolboxWidth_ = Math.max( + this.stableToolboxWidth_, + toolboxMetrics.width, + ); + } + if (isHorizontal && toolboxMetrics.height > 0) { + this.stableToolboxHeight_ = Math.max( + this.stableToolboxHeight_, + toolboxMetrics.height, + ); + } + + return { + ...toolboxMetrics, + width: isVertical ? this.stableToolboxWidth_ || toolboxMetrics.width : toolboxMetrics.width, + height: isHorizontal + ? this.stableToolboxHeight_ || toolboxMetrics.height + : toolboxMetrics.height, + }; + } + getAbsoluteMetrics() { const absolute = super.getAbsoluteMetrics(); const flyout = this.workspace_.getFlyout?.(); From a361e5e3736728fda58d24e207c69de09890800b Mon Sep 17 00:00:00 2001 From: Dr Tracy Gardner Date: Sun, 5 Apr 2026 17:54:46 +0100 Subject: [PATCH 3/3] Simplify overlay metrics fix to absolute-origin adjustment only --- main/blocklyinit.js | 66 --------------------------------------------- 1 file changed, 66 deletions(-) diff --git a/main/blocklyinit.js b/main/blocklyinit.js index 9b23fdf6..9feb22f1 100644 --- a/main/blocklyinit.js +++ b/main/blocklyinit.js @@ -607,44 +607,6 @@ export function initializeWorkspace() { export function createBlocklyWorkspace() { class OverlayMetricsManager extends Blockly.MetricsManager { - constructor(workspaceRef) { - super(workspaceRef); - this.stableToolboxWidth_ = 0; - this.stableToolboxHeight_ = 0; - } - - getToolboxMetrics() { - const toolboxMetrics = super.getToolboxMetrics(); - const Position = Blockly.utils.toolbox.Position; - const isVertical = - toolboxMetrics.position === Position.LEFT || - toolboxMetrics.position === Position.RIGHT; - const isHorizontal = - toolboxMetrics.position === Position.TOP || - toolboxMetrics.position === Position.BOTTOM; - - if (isVertical && toolboxMetrics.width > 0) { - this.stableToolboxWidth_ = Math.max( - this.stableToolboxWidth_, - toolboxMetrics.width, - ); - } - if (isHorizontal && toolboxMetrics.height > 0) { - this.stableToolboxHeight_ = Math.max( - this.stableToolboxHeight_, - toolboxMetrics.height, - ); - } - - return { - ...toolboxMetrics, - width: isVertical ? this.stableToolboxWidth_ || toolboxMetrics.width : toolboxMetrics.width, - height: isHorizontal - ? this.stableToolboxHeight_ || toolboxMetrics.height - : toolboxMetrics.height, - }; - } - getAbsoluteMetrics() { const absolute = super.getAbsoluteMetrics(); const flyout = this.workspace_.getFlyout?.(); @@ -663,34 +625,6 @@ export function createBlocklyWorkspace() { return adjusted; } - - getViewMetrics(opt_getWorkspaceCoordinates) { - const view = super.getViewMetrics(opt_getWorkspaceCoordinates); - const flyout = this.workspace_.getFlyout?.(); - if (!flyout || flyout.autoClose) return view; - - const flyoutMetrics = this.getFlyoutMetrics(); - const toolboxPosition = this.getToolboxMetrics().position; - const Position = Blockly.utils.toolbox.Position; - const scale = opt_getWorkspaceCoordinates ? this.workspace_.scale : 1; - const flyoutWidth = flyoutMetrics.width / scale; - const flyoutHeight = flyoutMetrics.height / scale; - const adjusted = { ...view }; - - if (toolboxPosition === Position.LEFT) { - adjusted.left -= flyoutWidth; - adjusted.width += flyoutWidth; - } else if (toolboxPosition === Position.RIGHT) { - adjusted.width += flyoutWidth; - } else if (toolboxPosition === Position.TOP) { - adjusted.top -= flyoutHeight; - adjusted.height += flyoutHeight; - } else if (toolboxPosition === Position.BOTTOM) { - adjusted.height += flyoutHeight; - } - - return adjusted; - } } // Register the custom renderer