From 1e2859d21a5ca9c4539ef9fdcc025691ce853f24 Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Fri, 21 Feb 2025 01:50:38 +0000 Subject: [PATCH 1/5] fix: Ensure visual indicating for focus loss. If the workspace loses focus, any existing block selection or cursor visuals should be hidden to represent that the focus has been lost. --- src/line_cursor.ts | 16 ++++++++++++++++ src/navigation.ts | 6 +++--- src/navigation_controller.ts | 5 +++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/line_cursor.ts b/src/line_cursor.ts index 4dafdb4f..e113ef8f 100644 --- a/src/line_cursor.ts +++ b/src/line_cursor.ts @@ -555,6 +555,22 @@ export class LineCursor extends Marker { this.updateFocusIndication(oldNode, newNode); } + override hide(): void { + super.hide(); + + // If there's a block currently selected, remove the selection since the + // cursor should now be hidden. + const curNode = this.getCurNode(); + if (curNode.getType() === ASTNode.types.BLOCK) { + const block = curNode.getLocation() as Blockly.BlockSvg; + if (!block.isShadow()) { + Blockly.common.setSelected(null); + } else { + block.removeSelect(); + } + } + } + /** * Implements fake selection of shadow blocks as described in * documentation for setCurNode. diff --git a/src/navigation.ts b/src/navigation.ts index d8b932d5..179b2952 100644 --- a/src/navigation.ts +++ b/src/navigation.ts @@ -544,7 +544,7 @@ export class Navigation { * - Resume editing by returning the cursor to its previous location, if any. * - Move the cursor to the top connection point on on the first top block. * - Move the cursor to the default location on the workspace. - * + * * @param workspace The main Blockly workspace. * @param keepPosition Whether to retain the cursor's previous position. */ @@ -1139,7 +1139,7 @@ export class Navigation { // Although it seems like this should never happen, the typings are wrong // in the base Marker class and this can therefore be null. if (this.markedNode) { - this.passiveFocusIndicator.show(this.markedNode); + // this.passiveFocusIndicator.show(this.markedNode); } } @@ -1149,7 +1149,7 @@ export class Navigation { * @param workspace The workspace. */ removeMark(workspace: Blockly.WorkspaceSvg) { - this.passiveFocusIndicator.hide(); + // this.passiveFocusIndicator.hide(); this.markedNode = null; } diff --git a/src/navigation_controller.ts b/src/navigation_controller.ts index 0c4affe0..ee1253a2 100644 --- a/src/navigation_controller.ts +++ b/src/navigation_controller.ts @@ -159,6 +159,11 @@ export class NavigationController { this.hasNavigationFocus = isFocused; if (isFocused) { this.navigation.focusWorkspace(workspace, true); + } else { + // Hide cursor to indicate lost focus. Also, mark the current node so that + // it can be properly restored upon returning to the workspace. + this.navigation.markAtCursor(workspace); + workspace.getCursor()?.hide(); } } From bba60fc24917c8dfecc2a45092d9db2d839eb71c Mon Sep 17 00:00:00 2001 From: Rachel Fenichel Date: Fri, 21 Feb 2025 18:26:48 -0800 Subject: [PATCH 2/5] feat: use CSS for passive focus on blocks and next connections --- src/passive_focus.ts | 13 +++++++------ test/index.html | 11 +++++++++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/passive_focus.ts b/src/passive_focus.ts index 78e718a0..c43a7f47 100644 --- a/src/passive_focus.ts +++ b/src/passive_focus.ts @@ -96,7 +96,11 @@ export class PassiveFocus { const block = node.getLocation() as BlockSvg; // Note that this changes rendering but does not change Blockly's // internal selected state. - block.addSelect(); + // If the block renders selected, the selection highlight is in + // front of the block's path and obscures these changes. + block.removeSelect(); + + utils.dom.addClass(block.pathObject.svgPath, 'passiveBlockFocus'); } /** @@ -106,9 +110,8 @@ export class PassiveFocus { */ hideAtBlock(node: ASTNode) { const block = node.getLocation() as BlockSvg; - // Note that this changes rendering but does not change Blockly's - // internal selected state. - block.removeSelect(); + + utils.dom.removeClass(block.pathObject.svgPath, 'passiveBlockFocus'); } /** @@ -122,8 +125,6 @@ export class PassiveFocus { 'width': 100, 'height': 5, 'class': 'passiveNextIndicator', - 'stroke': '#4286f4', - 'fill': '#4286f4', }); return indicator; } diff --git a/test/index.html b/test/index.html index 2ac168dd..19cebf82 100644 --- a/test/index.html +++ b/test/index.html @@ -96,6 +96,17 @@ #announcer { height: 25%; } + + .passiveBlockFocus.blocklyPath { + stroke-dasharray: 5 3; + stroke-width: 3; + stroke: #ff69b4; + } + + .passiveNextIndicator { + stroke: #ff69b4; + fill: #ff69b4; + } From dc5427dd4652b066b9ef0fd0b7d19e9d4eaa5e26 Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Wed, 5 Mar 2025 22:31:08 +0000 Subject: [PATCH 3/5] Attempt to use passive focus indicator via CSS. --- src/navigation.ts | 4 ++-- src/passive_focus.ts | 7 ++++++- test/index.html | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/navigation.ts b/src/navigation.ts index 179b2952..6c9c124c 100644 --- a/src/navigation.ts +++ b/src/navigation.ts @@ -1139,7 +1139,7 @@ export class Navigation { // Although it seems like this should never happen, the typings are wrong // in the base Marker class and this can therefore be null. if (this.markedNode) { - // this.passiveFocusIndicator.show(this.markedNode); + this.passiveFocusIndicator.show(this.markedNode); } } @@ -1149,7 +1149,7 @@ export class Navigation { * @param workspace The workspace. */ removeMark(workspace: Blockly.WorkspaceSvg) { - // this.passiveFocusIndicator.hide(); + this.passiveFocusIndicator.hide(); this.markedNode = null; } diff --git a/src/passive_focus.ts b/src/passive_focus.ts index c43a7f47..89a92b28 100644 --- a/src/passive_focus.ts +++ b/src/passive_focus.ts @@ -98,9 +98,11 @@ export class PassiveFocus { // internal selected state. // If the block renders selected, the selection highlight is in // front of the block's path and obscures these changes. - block.removeSelect(); + // block.removeSelect(); + console.log('DBG: Show at block'); utils.dom.addClass(block.pathObject.svgPath, 'passiveBlockFocus'); + block.pathObject.svgPath.style.strokeDasharray = '5 3'; } /** @@ -111,7 +113,10 @@ export class PassiveFocus { hideAtBlock(node: ASTNode) { const block = node.getLocation() as BlockSvg; + // Note that removing the class is insufficient to disable the dash. + console.log('DBG: Hide at block'); utils.dom.removeClass(block.pathObject.svgPath, 'passiveBlockFocus'); + block.pathObject.svgPath.style.strokeDasharray = 'none'; } /** diff --git a/test/index.html b/test/index.html index 19cebf82..8e5a7d0c 100644 --- a/test/index.html +++ b/test/index.html @@ -98,7 +98,7 @@ } .passiveBlockFocus.blocklyPath { - stroke-dasharray: 5 3; + /* stroke-dasharray: 5 3; */ stroke-width: 3; stroke: #ff69b4; } From 6c55893888c155ada02521264b9a7828a65a393d Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Wed, 5 Mar 2025 23:38:08 +0000 Subject: [PATCH 4/5] Add a workaround to fix passive indicator hiding. This was a workable solution found by Rachel with the explanation captured in a new line comment. --- src/navigation.ts | 9 +++++++++ src/passive_focus.ts | 12 ------------ test/index.html | 2 +- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/navigation.ts b/src/navigation.ts index 6c9c124c..3a0d21a5 100644 --- a/src/navigation.ts +++ b/src/navigation.ts @@ -559,6 +559,15 @@ export class Navigation { } if (this.markedNode) { + // Note that this hide happens twice, one before setCurNode() and once in + // removeMark. The latter is actually a logical no-op because setCurNode() + // will trigger a selection update of the currently marked node (if it's a + // block) and that, in turn, clones the underlying block's + // pathObject.svgPath. Since svgPath is updated to remove any passive + // focus indicator after selection clones it, the effect of removing the + // indicator doesn't do anything (hence it needs to be done *before* + // selection is added in order to immediately take effect). + this.passiveFocusIndicator.hide(); cursor.setCurNode(this.markedNode); this.removeMark(workspace); return; diff --git a/src/passive_focus.ts b/src/passive_focus.ts index 89a92b28..5a7d476a 100644 --- a/src/passive_focus.ts +++ b/src/passive_focus.ts @@ -94,15 +94,7 @@ export class PassiveFocus { */ showAtBlock(node: ASTNode) { const block = node.getLocation() as BlockSvg; - // Note that this changes rendering but does not change Blockly's - // internal selected state. - // If the block renders selected, the selection highlight is in - // front of the block's path and obscures these changes. - // block.removeSelect(); - - console.log('DBG: Show at block'); utils.dom.addClass(block.pathObject.svgPath, 'passiveBlockFocus'); - block.pathObject.svgPath.style.strokeDasharray = '5 3'; } /** @@ -112,11 +104,7 @@ export class PassiveFocus { */ hideAtBlock(node: ASTNode) { const block = node.getLocation() as BlockSvg; - - // Note that removing the class is insufficient to disable the dash. - console.log('DBG: Hide at block'); utils.dom.removeClass(block.pathObject.svgPath, 'passiveBlockFocus'); - block.pathObject.svgPath.style.strokeDasharray = 'none'; } /** diff --git a/test/index.html b/test/index.html index 8e5a7d0c..19cebf82 100644 --- a/test/index.html +++ b/test/index.html @@ -98,7 +98,7 @@ } .passiveBlockFocus.blocklyPath { - /* stroke-dasharray: 5 3; */ + stroke-dasharray: 5 3; stroke-width: 3; stroke: #ff69b4; } From bd74e05e90977e7ab8854eb5ba0bc89ef228364c Mon Sep 17 00:00:00 2001 From: Ben Henning Date: Tue, 11 Mar 2025 23:16:55 +0000 Subject: [PATCH 5/5] Use a better color for passive indicators. This color came at Rachel's suggestion. --- test/index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/index.html b/test/index.html index 19cebf82..6ceff580 100644 --- a/test/index.html +++ b/test/index.html @@ -100,12 +100,12 @@ .passiveBlockFocus.blocklyPath { stroke-dasharray: 5 3; stroke-width: 3; - stroke: #ff69b4; + stroke: #ffa200; } .passiveNextIndicator { - stroke: #ff69b4; - fill: #ff69b4; + stroke: #ffa200; + fill: #ffa200; }